home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Conversion / Convert_PICT / Source / PictConverter.m < prev    next >
Text File  |  1993-11-05  |  151KB  |  4,327 lines

  1. /***********************************************************************\
  2. Converter class for Convert PICT which converts graphics from PICT to eps formats.
  3. Copyright (C) 1993 David John Burrowes
  4.  
  5. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version.
  6.  
  7. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
  8.  
  9. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  10.  
  11. The author, David John Burrowes, can be reached at:
  12.     davidjohn@kira.net.netcom.com
  13.     David John Burrowes
  14.     1926 Ivy #10
  15.     San Mateo, CA 94403-1367
  16. \***********************************************************************/
  17.  
  18. #define VERSIONSTRING "Convert PICT 1.2"
  19.  
  20. /*
  21. ====================================================================
  22.     This is $Revision: 1.10 $ of this file
  23.     It was last modified by $Author: death $ on $Date: 93/04/04 23:29:57 $
  24. Note that this file was created while using the New Century Schoolbook Roman typeface.  You may find that some things line up strangely if you don't use that family.
  25.  
  26. History:
  27.     93.07.18    djb    Added support for     the user's having a choice of either writing out the
  28.                 piccomments as before, or having them ommitted.
  29.     93.08.01    djb    Finished Objective-C support for PicComments defined in tech notes.
  30.  
  31. $Log:    PictConverter.m,v $
  32. Revision 1.10  93/04/04  23:29:57  death
  33. Sun Apr  4 23:29:57 PDT 1993
  34.  
  35. Revision 1.9  93/01/09  21:07:09  death
  36. Sat Jan  9 21:07:09 PST 1993
  37.  
  38. Revision 1.8  93/01/01  11:51:17  death
  39. Fri Jan  1 11:51:17 PST 1993
  40.  
  41. Revision 1.7  92/12/31  15:33:55  death
  42. Thu Dec 31 15:33:55 PST 1992
  43.  
  44. Revision 1.6  92/12/05  23:06:28  death
  45. Sat Dec  5 23:06:28 PST 1992
  46.  
  47.  ====================================================================
  48.  */
  49.  
  50. #import "PictConverter.h" 
  51. #import "PICTFile.h"
  52. #import "PSFile.h"
  53. #import <stdio.h>
  54. #import <string.h>
  55. #import <strings.h>
  56. #import <stdlib.h>
  57. #include <time.h>
  58. #import <architecture/byte_order.h>    // for big/little endian conversins
  59. #import "RegionConverter.h"
  60. #import "MacToNeXTText.h"
  61. @implementation PictConverter
  62.  
  63. /*
  64.     Layout of the groups of routines in this file (in order)
  65.         Administrative/ setup
  66.         High level opcode parsers
  67.         General opcode processing
  68.         Processing utilities (e.g. WriteRect)
  69.         Primary data conversion routines
  70.         Bitmap and pattern processing (about 25-30% of the file)
  71.     Notes:
  72.         Warning.  In bitmap routines, we routinely write out > and 80 as terminators for the
  73.         various PS filters.  Make any changes to these parts with caution, since PS lvl 1 code
  74.         depends on precisely the number of bytes they are (including end of lines)
  75.         In PS code, if you remove rapping for oval sizes that are too big, you can get neat
  76.         results. =)
  77.     Enhancements:
  78.         The percent indicator on the conversion window is not updated when you'd think it
  79.         should be (display is always one step behind what it thinks it's drawn , Ithink)
  80.         Convert packed color bitmaps straight through, rather than unpack and then
  81.         repack?  (Might be able to do similar for B&W, by inverting in place)
  82.         Warning: The signs of arguments of some opcodes, esp. in Miscellaneous group, have
  83.         not been thoroughly tested.
  84.         Enhance overall error checking, including providing gracefull aborting (what if
  85.         pixmap has unfamiliar values?
  86.         My treatment of RGB color values may be bad, in that I'm assuming they are
  87.         8 bit values in a 16 space.  This may not be accurate. 
  88. */
  89.  
  90.  
  91.  
  92.  
  93. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  94. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  95. //    Administrative/setup methods
  96. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  97. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  98.  
  99.  
  100. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  101. //    Method:        init
  102. //    Parameters:    none
  103. //    Returns:     self
  104. //    Stores:        none
  105. //    Description:
  106. //        This initializes the instance variables of the created object.
  107. //    History:
  108. //        93.07.18    djb    Added initializing of the new instance variable PicCommentOp...
  109. //    Bugs:
  110. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  111. - init
  112. {
  113.     sourceFile = NullInstance;
  114.     destFile = NullInstance;
  115.  
  116.     [super   init];
  117.     //
  118.     //    The following are sorted by opcode number, basically
  119.     //
  120.     UsedPatterns = NO;
  121.     UsedColors = NO;
  122.     UsedLines = NO;
  123.     UsedText = NO;
  124.     UsedRectangles = NO;
  125.     UsedRoundRectangles = NO;
  126.     UsedOvals = NO;
  127.     UsedArcs = NO;
  128.     UsedPolygons = NO;
  129.     UsedRegions = NO;
  130.     UsedBitmaps = NO;
  131.     UsedComments = NO;
  132.     UsedMiscellaneous = NO;
  133.  
  134.     CodeDir = NewCString(0);
  135.  
  136.     PackingSetting = YES;
  137.  
  138.     textConverter = [[MacToNeXTText  alloc] init];
  139.     ConvertCurrentCharacters = YES;
  140.     UsersCharConvertChoice = NO;
  141.     PicCommentOperation = ConvertPicComments;
  142.     return self;
  143. }
  144.  
  145. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  146. //    Method:        free
  147. //    Parameters:    none
  148. //    Returns:     self
  149. //    Stores:        none
  150. //    Description:
  151. //        This disposes of the CodeDir instance variable
  152. //    Bugs:
  153. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  154. - free
  155. {
  156.     FreeCString(CodeDir);
  157.     [textConverter   free];
  158.     [super   free];
  159.     return self;
  160. }
  161.  
  162. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  163. //    Method:        SetImagePacking:CLUTIncluding:AndCodeSet:
  164. //    Parameters:    three boolean values
  165. //    Returns:     self
  166. //    Stores:        none
  167. //    Description:
  168. //        This routine allows a caller to change two settings that affect the behavior of
  169. //        an instance of this class.  The three values are:
  170. //            - whether we pack bitmap when we write them out, or leave them unpacked
  171. //            - Where we should locate the PS code to include with the code we generate.
  172. //    Bugs:
  173. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  174. - SetImagePacking: (Boolean) packimages UsingPSIn: (CString) newCodeDirectory
  175. {
  176.     PackingSetting = packimages;
  177.     if (newCodeDirectory != NullCString)
  178.     {
  179.         FreeCString(CodeDir);
  180.         CodeDir = NewCString(strlen(newCodeDirectory));
  181.         strcpy(CodeDir, newCodeDirectory);
  182.     }
  183.     return self;
  184. }
  185.  
  186.  
  187. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  188. //    Method:        SetConvertAllChars:
  189. //    Parameters:    boolean value
  190. //    Returns:     self
  191. //    Stores:        none
  192. //    Description:
  193. //        Tweaks one aspect of this application's character conversion.  If YES, then
  194. //        chars in unfamiliar families will be converted.  If NO, then they won't.  
  195. //    History:
  196. //        93.07.18    djb    Removed a semicolon from the end of the method name.
  197. //    Bugs:
  198. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  199. - SetConvertAllChars: (Boolean) convertAll
  200. {
  201.     UsersCharConvertChoice = convertAll;
  202.     return self;
  203. }
  204.  
  205.  
  206. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  207. //    Method:        SetPicCommentConversion:
  208. //    Parameters:    An enumerated value indicating what kind of piccomment conversion
  209. //                should be done hereafter.
  210. //    Returns:     self
  211. //    Stores:        none
  212. //    Description:
  213. //        This sets my instance variable PicCommentOperation to the specified
  214. //        value.  This allows someone else to dictate how I should deal with PicComments
  215. //        until this setting is reset.
  216. //    History:
  217. //        93.07.18    djb    Created
  218. //    Bugs:
  219. //        This doesn't assure that the enumerated parameter is a 'good' value.
  220. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  221. - SetPicCommentConversion: (PicCommentOpType) picConversion
  222. {
  223.     PicCommentOperation = picConversion;
  224.     return self;
  225. }
  226.  
  227.  
  228.  
  229. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  230. //    Method:        isThisAGoodFile:
  231. //    Parameters:    A Pict File instance
  232. //    Returns:     YES if it is, NO if it isn't.
  233. //    Stores:        none
  234. //    Description:
  235. //        Get the pict file's version number.  If it's 1 or 2, then return that it is a good file.
  236. //        This should never answer 'NO', because the pict file itself will have failed to open
  237. //        fail to open if it thinks the file is not legit.
  238. //    Bugs:
  239. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  240. - (Boolean) isThisAGoodFile: theFile
  241. {
  242.     Integer            version;
  243.     Boolean            result    = NO;
  244.  
  245.     version = [theFile   GetVersion];
  246.     if ((version== 2) || (version == 1))
  247.         result = YES;
  248.     else
  249.     {
  250.         [self  PutCString: "This doesn't look like a PICT file to me (could not find the `version' opcode).  Proceed with extreme caution." Into: SECOND_RESULT];
  251.         result = NO;
  252.     }
  253.     return result;
  254. }
  255.  
  256.  
  257. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  258. //    Method:        ConvertPICTfile:ToEPSfile:
  259. //    Parameters:
  260. //        The PICT file to convert from
  261. //        the eps file to store into
  262. //    Returns:     errors
  263. //    Stores:        none
  264. //    Description:
  265. //        Ths is the main conversion routine.  It converts a pict file into the specified
  266. //        postscript file.  After initializations, this involves a couple steps: convert all
  267. //        the PICT opcodes into a temporary file.  While doing this, keep track of what
  268. //        types of opcodes we have used.  For instance, if we get a call to the FrameRect
  269. //        opcode, we will set UsedRectangles to YES.  When this is done, write a header
  270. //        onto the eps file, and then copy over all the PS groups that were actually used
  271. //        (this allows the destination PS file to be smaller than if we copied everything).
  272. //        After this, copy the contents of the temporary file to the PS file (the stuff was
  273. //        written to the temporary file earlier, because we needed to get the header
  274. //        and group definitions written before it).  Finally, write the trailing restore, etc.
  275. //    Bugs:
  276. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  277. - ConvertPICTfile: pictFile ToEPSfile: epsfile
  278. {
  279.     Boolean        finished            = NO;
  280.     Integer        opcodeCount        = 0;
  281.     Real            fileSize             = [pictFile   FileSize] * 1.0;
  282.     CString        tempString        = NewCString(100);
  283.     PICTRect*    bounds             = [pictFile   GetBounds];
  284.     
  285.     //
  286.     //    Initalize the PS group flags, so we don't include PS code we don't want.
  287.     //
  288.     UsedPatterns = NO;
  289.     UsedColors = NO;
  290.     UsedLines = NO;
  291.     UsedText = NO;
  292.     UsedRectangles = NO;
  293.     UsedRoundRectangles = NO;
  294.     UsedOvals = NO;
  295.     UsedArcs = NO;
  296.     UsedPolygons = NO;
  297.     UsedRegions = NO;
  298.     UsedComments = NO;
  299.     UsedMiscellaneous = NO;
  300.     UsedBitmaps = NO;
  301.     //
  302.     //
  303.     //
  304.     ConvertCurrentCharacters = YES;
  305.     //
  306.     //    Set the instance variable 'sourceFile' to be the pict file,
  307.     //    set the destFile to be a temporary file, for now.
  308.     //
  309.     sourceFile = pictFile;
  310.     destFile = [[PSFile alloc] initAndUseTemporary];
  311.     if ([destFile   GetErrorCode] == ERR_OK)
  312.         [destFile   CreateAndOpenFor: FILE_READWRITE];
  313.     if  ([destFile   GetErrorCode] != ERR_OK) 
  314.     {
  315.         [self   StoreErrorCode: ERR_CREATEFAILED
  316.             AndText: "Could not create a necessary, temporary, file"];
  317.         [destFile   free];
  318.         destFile = NullInstance;
  319.     }
  320.     else
  321.     {
  322.         //
  323.         //    Write the initiating 'startPict' which will be balanced, later, by the endPict opcode 0xFF.
  324.         //
  325.         [destFile   WriteInteger:  [sourceFile GetVersion]];
  326.         [self   WritePSProcedureName: "startPict"];
  327.         //
  328.         //    With source and destination file established, convert all the opcodes..
  329.         //    (Let out manager know how the conversion process is going every 10 opcodes)
  330.         //
  331.         while (finished == NO)
  332.         {
  333.             finished = [self ParseOpcode: [sourceFile   GetOpcode]];
  334.             if ((opcodeCount % 10) == 0)
  335.                 if ( [myManager   respondsTo:@selector(SetPercentageDone:)] ) 
  336.                     [myManager   SetPercentageDone: ([sourceFile   GetCurrentPosition] * 100.0) /  fileSize];
  337.         }
  338.         //
  339.         //    If no error occurred, then proceed
  340.         //
  341.         if ([self   GetErrorCode] >= ERR_OK)
  342.         {
  343.             //
  344.             //    Write the PS Header and prolog of group ps code  Add the 'save' line.
  345.             //
  346.             [self   BuildHeaderInto: epsfile];
  347.             [self   BuildPrologInto: epsfile];
  348.             [epsfile   WritePSLine: "save"];
  349.             [epsfile   ForceNewLine];
  350.             //
  351.             //    Write the matrix to compensate for the PICT and PS coordinate systems
  352.             //
  353.             [epsfile   WriteTextUsing: tempString
  354.                 WithFormat: "[1 0 0 -1 %d %d] concat\n", -1*bounds->left, bounds->bottom];
  355.             //
  356.             //    Write all the data from the conversion of the opcodes, and then the terminating 'restore'.
  357.             //
  358.             [epsfile   AppendFrom: destFile];
  359.             [epsfile   ForceNewLine];
  360.             [epsfile   WritePSLine: "restore"];
  361.         }
  362.         [destFile   CloseAndDelete];    // Remember that this is the temp file.  The 'destination'  of just the opcode conversion
  363.         [destFile   free];
  364.     }
  365.     FreeCString(tempString);
  366.     FreeByteString((ByteString)bounds);
  367.     return self;
  368. }
  369.  
  370.  
  371. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  372. //    Method:        SimpleStringConvert:
  373. //    Parameters:    A CString structure
  374. //    Returns:     A converted CString
  375. //    Stores:        none
  376. //    Description:
  377. //        This is a quick hack that takes a string, and turns it into another string with
  378. //        non-printable characters escaped, and (\) all escaped as well.  The resulting string
  379. //        is returned (truncated to 255 chars if necessary)
  380. //    Bugs:
  381. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  382. - (CString) SimpleStringConvert: (CString) theString
  383. {
  384.     CString    filteredString;
  385.     CString    tempString;
  386.     PositiveInteger    filterIndex;
  387.     PositiveInteger    index;
  388.     PositiveInteger    newLength = strlen(theString);
  389.     //
  390.     //    Now, filter this string, replacing certain troublesome characters with
  391.     //    escaped equivalents.
  392.     //
  393.     filteredString = NewCString(newLength*4); // worst case each all will become \ddd
  394.     filterIndex = 0;
  395.     for (index = 0; index < newLength; index++)
  396.     {
  397.         if    ( ( (PositiveInteger) theString[index] < 32 ) ||
  398.             (PositiveInteger) theString[index] > 126 )
  399.         {
  400.             tempString = NewCString(4);
  401.             //
  402.             //    93.01.31    djb    OOPS!  Had been using %.3u, not octal!
  403.             //
  404.             sprintf(tempString, "\\%.3o", (unsigned int) theString[index]);
  405.             strcat(filteredString, tempString);
  406.             FreeCString(tempString);
  407.             filterIndex += 4;
  408.         }
  409.         else
  410.         {
  411.             switch (theString[index])
  412.             {
  413.                 case '\\' :
  414.                     strcat(filteredString, "\\\\");
  415.                     filterIndex += 2;
  416.                     break;
  417.                 case '(' :
  418.                     strcat(filteredString, "\\(");
  419.                     filterIndex += 2;
  420.                     break;
  421.                 case ')' :
  422.                     strcat(filteredString, "\\)");
  423.                     filterIndex += 2;
  424.                     break;
  425.                 default :
  426.                     filteredString[filterIndex] = theString[index];
  427.                     filterIndex ++;
  428.                     filteredString[filterIndex] = EndOfCString; // put a null back on.
  429.                     break;
  430.             }
  431.         }
  432.     
  433.     }
  434.     //
  435.     //    Don't let the string be longer than 255 chars (p. 639 of Big fat red ps book)
  436.     //
  437.     if (strlen(filteredString) > 255)
  438.         filteredString[255] = EndOfCString;
  439.     FreeCString(theString);
  440.     return filteredString;
  441. }
  442.  
  443.  
  444. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  445. //    Method:        BuildHeaderInto:
  446. //    Parameters:    a PSfile object.
  447. //    Returns:     errors
  448. //    Stores:        none
  449. //    Description:
  450. //        When we're ready to start building the output PS file.
  451. //        We build a nice standard PS header here. 
  452. //    Bugs:
  453. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  454.  
  455. - BuildHeaderInto: thisFile
  456. {
  457.     CString        tempString        = NewCString(255);
  458.     CString        tempBasename;
  459.     PICTRect*    bounds             = [sourceFile   GetBounds];
  460.     Integer        thetime;
  461.     CString        timeString;
  462.     //
  463.     //    Write out inital lines.
  464.     //    
  465.     [thisFile   WriteComment: "!PS-Adobe-3.0 EPSF-3.0"];
  466.     //
  467.     //    Write as an EPS bounding box
  468.     //
  469.     [thisFile   WriteDSCCommentUsing: tempString
  470.         WithFormat: "BoundingBox: %d %d %d %d",0, 0,
  471.         (bounds->right - bounds->left), (bounds->bottom)-(bounds->top)];
  472.     //
  473.     //    Record the name of the file, and close off the beginning comments.
  474.     //    
  475.     tempBasename = [self  SimpleStringConvert: [sourceFile   GetBasename]];
  476.     [thisFile   WriteDSCCommentUsing: tempString
  477.         WithFormat: "Title: (%s)", tempBasename];
  478.     [thisFile   WriteDSCCommentUsing: tempString
  479.         WithFormat: "Creator: (%s)", VERSIONSTRING];
  480.     thetime = time(NULL);
  481.     timeString = (CString) ctime(&thetime);
  482.     sprintf(tempString, "CreationDate: (%s", timeString); 
  483.     tempString[strlen(tempString)-1] = EndOfCString; // ctime puts a \n on which we don't want
  484.     strcat(tempString,")");
  485.     [thisFile WriteDSCComment: tempString];
  486.     [thisFile   WriteDSCComment: "EndComments"];
  487.     FreeCString(tempBasename);
  488.     
  489.     FreeCString(tempString);
  490.     FreeByteString((ByteString)bounds);
  491.     return self;
  492. }
  493.  
  494.  
  495. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  496. //    Method:        AppendFile:
  497. //    Parameters:    the pathname of a file, and a file instance to append it to.
  498. //    Returns:     errors
  499. //    Stores:        none
  500. //    Description:
  501. //        Given a file, and the path to a file, open the path, and append its contents
  502. //        to the instance.  If we fail to do this, report an error.
  503. //    Bugs:
  504. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  505.  
  506. - AppendFile: (CString) codeFile To: thisFile
  507. {
  508.     Instance    tempFile;
  509.     
  510.     tempFile = [[PSFile alloc] initAndUse: codeFile];
  511.     if ([tempFile   GetErrorCode] == ERR_OK)
  512.         [tempFile   OpenExistingFor: FILE_READ];
  513.     if  ([tempFile   GetErrorCode] != ERR_OK) 
  514.         [self   StoreErrorCode: ERR_OPENFAILED
  515.             AndText: "Could not open a file of necessary PS code"];
  516.     else
  517.     {
  518.         [thisFile   AppendFrom: tempFile];
  519.         if  ([thisFile   GetErrorCode] != ERR_OK) 
  520.             [self   StoreErrorCode: ERR_APPENDFAILED
  521.                 AndText: "Could not append a file of necessary PS code"];
  522.         [tempFile   Close];
  523.     }
  524.     [tempFile   free];
  525.     return self;
  526. }
  527.  
  528.  
  529. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  530. //    Method:        BuildPrologInto:
  531. //    Parameters:    A text file object.
  532. //    Returns:     errors
  533. //    Stores:        none
  534. //    Description:
  535. //        When we're ready to start building the output PS file, we need to stick all the
  536. //        PostScript code and procedures into the file.   This routine checks each group
  537. //        flag, and if it is set, dumps the appropriate PS out.
  538. //        Note: we find the path that leads us to the files of PS code that we might
  539. //        want to append.  For each of these, if the relevant flag indicates we
  540. //        should, we add the file name to the path, call the routine to append
  541. //        that file, and then strip the name off the path so we can reuse it.
  542. //        Note that we set no errors, but rely on AppendFile: to do so.
  543. //    Bugs:
  544. //        We should report when the PS code directory isn't even there.  however,
  545. //        this requires more work than I'm willing to do at the moment.  (stat() is not
  546. //        as reliable as I'd feel comfortable, since the man page says it barfs if there is
  547. //        an 8 bit character in the path (gads)).
  548. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  549.  
  550. - BuildPrologInto: thisFile
  551. {
  552.     CString        fileName = NewCString(strlen(CodeDir)+20);
  553.     Integer        pathlength;
  554.  
  555.     [self   ResetResults];
  556.     
  557.     [thisFile   WriteDSCComment: "Begin Prolog"];
  558.     strcpy(fileName, CodeDir);
  559.     pathlength = strlen (fileName);
  560.     //
  561.     //    Append all the common code
  562.     //
  563.     strcat(fileName, "Common");    
  564.     [self   AppendFile: fileName To: thisFile];
  565.     fileName[pathlength] = EndOfCString;
  566.     //
  567.     //    Miscellaneous
  568.     //
  569.     if (UsedMiscellaneous == YES)
  570.     {
  571.         strcat(fileName, "Miscellaneous");    
  572.         [self   AppendFile: fileName To: thisFile];
  573.         fileName[pathlength] = EndOfCString;
  574.     }
  575.     //
  576.     //    Patterns
  577.     //
  578.     if (UsedPatterns == YES)
  579.     {
  580.         strcat(fileName, "Patterns");
  581.         [self   AppendFile: fileName To: thisFile];
  582.         fileName[pathlength] = EndOfCString;
  583.     }
  584.     //
  585.     //    Colors
  586.     //
  587.     if (UsedColors == YES)
  588.     {
  589.         strcat(fileName, "Colors");
  590.         [self   AppendFile: fileName To: thisFile];
  591.         fileName[pathlength] = EndOfCString;
  592.     }
  593.     //
  594.     //    lines
  595.     //
  596.     if (UsedLines == YES)
  597.     {
  598.         strcat(fileName, "Lines");    
  599.         [self   AppendFile: fileName To: thisFile];
  600.         fileName[pathlength] = EndOfCString;
  601.     }
  602.     //
  603.     //    text
  604.     //
  605.     if (UsedText == YES)
  606.     {
  607.         strcat(fileName, "Text");    
  608.         [self   AppendFile: fileName To: thisFile];
  609.         fileName[pathlength] = EndOfCString;
  610.     }
  611.     //
  612.     //    Rects
  613.     //
  614.     if (UsedRectangles == YES)
  615.     {
  616.         strcat(fileName, "Rectangles");
  617.         [self   AppendFile: fileName To: thisFile];
  618.         fileName[pathlength] = EndOfCString;
  619.     }
  620.     //
  621.     //    Roundrects
  622.     //
  623.     if (UsedRoundRectangles == YES)
  624.     {
  625.         strcat(fileName, "RoundRectangles");
  626.         [self   AppendFile: fileName To: thisFile];
  627.         fileName[pathlength] = EndOfCString;
  628.     }
  629.     //
  630.     //    ovals
  631.     //
  632.     if (UsedOvals == YES)
  633.     {
  634.         strcat(fileName, "Ovals");
  635.         [self   AppendFile: fileName To: thisFile];
  636.         fileName[pathlength] = EndOfCString;
  637.     }
  638.     //
  639.     //    arcs
  640.     //
  641.     if (UsedArcs == YES)
  642.     {
  643.         strcat(fileName, "Arcs");
  644.         [self   AppendFile: fileName To: thisFile];
  645.         fileName[pathlength] = EndOfCString;
  646.     }
  647.     //
  648.     //    polygons
  649.     //
  650.     if (UsedPolygons == YES)
  651.     {
  652.         strcat(fileName, "Polygons");
  653.         [self   AppendFile: fileName To: thisFile];
  654.         fileName[pathlength] = EndOfCString;
  655.     }
  656.     //
  657.     //    regions
  658.     //
  659.     if (UsedRegions == YES)
  660.     {
  661.         strcat(fileName, "Regions");
  662.         [self   AppendFile: fileName To: thisFile];
  663.         fileName[pathlength] = EndOfCString;
  664.     }
  665.     //
  666.     //    bitmaps
  667.     //
  668.     if (UsedBitmaps == YES)
  669.     {
  670.         strcat(fileName, "Bitmaps");
  671.         [self   AppendFile: fileName To: thisFile];
  672.         fileName[pathlength] = EndOfCString;
  673.     }
  674.     //
  675.     //    Comments
  676.     //
  677.     if (UsedComments == YES)
  678.     {
  679.         strcat(fileName, "Comments");
  680.         [self   AppendFile: fileName To: thisFile];
  681.         fileName[pathlength] = EndOfCString;
  682.     }
  683.     FreeCString(fileName);
  684.     [thisFile   WriteDSCComment: "End Prolog"];
  685.     return self;
  686. }
  687.  
  688.  
  689.  
  690. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  691. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  692. //                    HIGH LEVEL OPCODE PROCESSING
  693. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  694. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  695.  
  696.  
  697.  
  698. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  699. //    Method:        ParseOpcode
  700. //    Parameters:    A PICT opcode
  701. //    Returns:     YES if something went wrong or we reached the end of the pict file
  702. //    Stores:        none
  703. //    Description:
  704. //        This method takes an opcode, and passes it on to a particular method that deal
  705. //        with processing a particular group of opcodes.  This routine, and the ones it
  706. //        calls, then, essentially make up a giant switch statement that has been
  707. //        broken up for legibility's sake.
  708. //        These methods are the heard of this object.  Given an opcode, it reads the appropriate
  709. //        arguments, and writes appropriate postscript calls out to the output file.  Note that
  710. //        this does not generate the actual postscript procedures that will be needed to image
  711. //        this, but rather just the calls to some procedures.  Those PS procedures must
  712. //        be created independantly of this object.
  713. //        NOTE: The following code basically presumes you know something about PICT files.
  714. //        It's organization is basically:  throw the specified opcode through a giant switch
  715. //        statement. If, for some reason, it isn't one of the defined opcodes, a default entry
  716. //        will try to consume its  data so no harm is done.
  717. //        If you know nothing about PICT stuff, these are the sources that I've used to figure out 
  718. //        what is in one (aside from mucking around with occasional PICT files by hand): Inside
  719. //        Mac V p.84-105, The Pict.r file which comes with MPW (I think the partial path is
  720. //        :MPW:Includes:RIncludes:Pict.r), Tech Note 21, and a bit of guessing.  =)
  721. //    History:
  722. //        93.07.18    djb    Changed Compiler told me that ((opCode >=0x00) && (opCode <=0x1F))
  723. //                    : comparison is always 1 due to limited range of data type.  I said 'huh?
  724. //                    opCode is 16bits!  There should be plenty of room'.  So, I poked and poked,
  725. //                    and eventualy it dawned on my thick head that since opCode is an
  726. //                    unsigned quantity, it would always be >=0.  Duh.  Kinda funny, for me,
  727. //                    though.  Needless to say, I pulled that bit out!
  728. //                    Also, moved comment processing to a separate routine call.
  729. //    History:
  730. //        93.08.21    djb    used 'endFound' flag to catch error flag from parsebitmap
  731. //                    definitely a hack, but for now we'll live.
  732. //    Bugs:
  733. //        Ignoring error flags
  734. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  735.  
  736. -(Boolean) ParseOpcode: (PICTOpcode) opCode
  737. {
  738.     Boolean    endFound = NO;
  739.     //
  740.     //    Now, try to parse the message.
  741.     //
  742.     if (opCode == 0xFF)
  743.         endFound = YES;
  744.  
  745.     if ( (opCode <=0x1F)   || (opCode == 0xFF)  || (opCode == 0x0C00))
  746.         [self   ParseMiscOpcode: opCode];
  747.     else if ( (opCode >= 0x20) && (opCode <=0x27))
  748.         [self   ParseLineOpcode: opCode];
  749.     else if ( (opCode >= 0x28) && (opCode <=0x2F) ) 
  750.         [self   ParseTextOpcode: opCode];
  751.     else if ( (opCode >= 0x30) && (opCode <=0x3F) )
  752.         [self   ParseRectangleOpcode: opCode];
  753.     else if ( (opCode >= 0x40) && (opCode <=0x4F) )
  754.         [self   ParseRoundRectangleOpcode: opCode];
  755.     else if ( (opCode >= 0x50) && (opCode <=0x5F) )
  756.         [self   ParseOvalOpcode: opCode];
  757.     else if ( (opCode >= 0x60) && (opCode <=0x6F) )
  758.         [self   ParseArcOpcode: opCode];
  759.     else if ( (opCode >= 0x70) && (opCode <=0x7F) )
  760.         [self   ParsePolygonOpcode: opCode];
  761.     else if ( (opCode >= 0x80) && (opCode <=0x8F) )
  762.         [self   ParseRegionOpcode: opCode];
  763.     else if ( (opCode >= 0x90) && (opCode <=0x9F) )
  764.         endFound = [self  ParseBitmapOpcode: opCode];
  765.     else if ((opCode == 0xA0)  || (opCode == 0xA1))
  766.         [self   ParseCommentOpcode: opCode];
  767.     else if ((opCode >= 0x00A2) && (opCode != 0x0C00) && (opCode != 0x00FF))
  768.         {
  769.             //
  770.             //    There are a bunch of reserved opcodes defined by apple.  On the off chance
  771.             //    we get a picture that makes use of one of them, the following will just
  772.             //    skip over its data and ignore it.
  773.             //
  774.             //
  775.             // Opcodes 0x8000 to 0x80FF and 0x00B0 to 0x00CF have no data to
  776.             // consume.
  777.             //
  778.             if (opCode >= 0x8100)
  779.                 [self Skip4PlusData];
  780.             //
  781.             // Opcodes 0x8000 to 0x80FF have no data to consume.
  782.             //
  783.             if ((opCode >= 0x7F00) && (opCode <= 0x7FFF))
  784.                 [sourceFile AdvanceBytes: 254];
  785.             //
  786.             // It is not clear what values follow these next opcodes.  I'm guessing 4
  787.             //
  788.             if ((opCode >= 0x0C01) && (opCode < 0x7F00))
  789.                 [sourceFile AdvanceBytes: 4];
  790.             if ((opCode >= 0x0200) && (opCode < 0xBFF))
  791.                 [sourceFile AdvanceBytes: 4];
  792.             if ((opCode >= 0x0100) && (opCode < 0x1FF))
  793.                 [sourceFile AdvanceBytes: 2];
  794.             if ((opCode >= 0x00D0) && (opCode <= 0x00FE))
  795.                 [self Skip4PlusData];
  796.             //
  797.             // Opcodes 0x00B0 to 0x00CF have no data to consume.
  798.             //
  799.             if ((opCode >= 0x00A2) && (opCode <= 0x00AF))
  800.                 [self Skip2PlusData];
  801.         }
  802.         else
  803.         {
  804.             //
  805.             //    Something is very weird if we get here, because all opcodes should have
  806.             //    been consumed above.
  807.             //
  808.             endFound = YES;
  809.         }
  810.     return endFound;
  811. }
  812.  
  813.  
  814. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  815. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  816. //                    OPCODE PROCESSING
  817. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  818. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  819.  
  820.  
  821.  
  822. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  823. //    Method:        ParseMiscOpcode:
  824. //    Parameters:
  825. //        A PICT opcode code
  826. //    Returns:     true if anything goes wrong
  827. //    Stores:        none  explicitly (subcalls may)
  828. //    Description:
  829. //        This is one segment of the giant switch that parses pict opcodes.
  830. //        This one deals with all the opcodes that do miscellaneous things
  831. //        (that is, that aren't part of some well defined greater group like the text
  832. //        opcodes, or the region ones, etc).  IT also includes opcodes (e.g. txFace)
  833. //        which logically belong to others, but weren't worth making specialized tests for
  834. //        above just so we could call this like that.
  835. //    History:
  836. //        93.07.18    djb    Moved PicComment processing into another routine.
  837. //        93.08.15    djb    Added HeaderOp for IM v. 6 format.
  838. //    Bugs:
  839. //        The rectangle in a -2 headerop should be being used for the 
  840. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  841. - (Boolean) ParseMiscOpcode: (PICTOpcode) opcode
  842. {
  843.     Boolean    error    = NO;
  844.     CString    buffer;
  845.     Integer    tempInt;
  846.     PICTPoint* numerator;
  847.     PICTPoint* denominator;
  848.     Integer    version;
  849.     Signed32Bits    temp2;
  850.     Signed32Bits    tempsize;
  851.     //
  852.     //    Process the opcode
  853.     //
  854.     switch (opcode)
  855.     {
  856.         case 0x00 : // NOP opcode.  Do nothing
  857.             break;
  858.         case 0x01 : // Define clip region.
  859.             // Uses common definitions.
  860.             [self   ConvertRegion];
  861.             [self   WritePSProcedureName: "QDclip"];
  862.              break;
  863.         case 0x02 : // bk Pat
  864.             UsedPatterns = YES;
  865.             [self   ConvertPict1Pattern];
  866.             [self   WritePSProcedureName: "bkPat"];
  867.              break;
  868.         case 0x03 : // Set type family to use
  869.             UsedText = YES;
  870.             [self   ConvertFamily];
  871.             [self   WritePSProcedureName: "txFont" ];
  872.              break;
  873.         case 0x04 : // Set type style to use
  874.             UsedText = YES;
  875.             [self  ConvertFace];
  876.             [self  WritePSProcedureName: "txFace" ];
  877.              break;
  878.         case 0x05 : // Set type mode
  879.             UsedText = YES;
  880.             [self   ConvertMode];
  881.             [self   WritePSProcedureName: "txMode" ];
  882.              break;
  883.         case 0x06 : // Set space extra
  884.             //
  885.             //    a fixed won't have more than 9 digits after the decimal place,
  886.             //    (by my calculator ( 1/(2**16)))
  887.             //
  888.             UsedText = YES;
  889.             buffer = NewCString(15);
  890.             [destFile   WriteTextUsing: buffer
  891.                 WithFormat: "%.9f ", [sourceFile GetFixedNumber]];
  892.             [self   WritePSProcedureName: "spExtra" ];
  893.             FreeCString(buffer);
  894.              break;
  895.         case 0x07 : // Set pen size
  896.             UsedMiscellaneous = YES;
  897.             tempInt =  [sourceFile   GetINTEGER];  // can it be negative?
  898.             [destFile   WriteInteger:  [sourceFile   GetINTEGER]]; // width
  899.             [destFile   WriteInteger:  tempInt]; // height
  900.              [self   WritePSProcedureName: "pnSize" ];
  901.              break;
  902.         case 0x08 : // Set pen mode
  903.             UsedMiscellaneous = YES;
  904.             [self   ConvertMode];
  905.             [self   WritePSProcedureName: "pnMode" ];
  906.              break;
  907.         case 0x09 : // Pen Pat
  908.             UsedPatterns = YES;
  909.             [self   ConvertPict1Pattern];
  910.             [self   WritePSProcedureName: "pnPat"];
  911.              break;
  912.         case 0x0a : // fill Pat
  913.             UsedPatterns = YES;
  914.             [self   ConvertPict1Pattern];
  915.             [self   WritePSProcedureName: "fillPat"];
  916.              break;
  917.         case 0x0B : // Oval size (x and y)
  918.             UsedRoundRectangles = YES;
  919.             [self   WritePoint: [sourceFile   GetPoint] ];
  920.             [self   WritePSProcedureName: "ovSize" ];
  921.              break;
  922.         case 0x0C : // Origin (dh and dv)
  923.             UsedMiscellaneous = YES;
  924.             [destFile   WriteInteger: -1* [sourceFile GetINTEGER]]; // dh
  925.             [destFile   WriteInteger:  -1*[sourceFile GetINTEGER]];  // dv
  926.             [self   WritePSProcedureName: "origin" ];
  927.              break;
  928.         case 0x0D : // TextSize
  929.             //
  930.             //    I can't tell if parameter should be signed integers or not
  931.             //
  932.             UsedText = YES;
  933.             [destFile   WriteInteger:  [sourceFile   GetINTEGER]];
  934.             [self   WritePSProcedureName: "txSize" ];
  935.              break;
  936.         case 0x0E : // FgColor
  937.             UsedColors = YES;
  938.             [self   ConvertOldColor];
  939.             [self   WritePSProcedureName: "fgColor"];
  940.              break;
  941.         case 0x0F : // BkColor
  942.             UsedColors = YES;
  943.             [self   ConvertOldColor];
  944.             [self   WritePSProcedureName: "bkColor"];
  945.              break;
  946.         case 0x10: // Text ratio
  947.             UsedText = YES;
  948.             //
  949.             //    presumably these are unsigned, but again, Apple calls them points.
  950.             //
  951.             numerator = [sourceFile   GetPoint];
  952.             denominator = [sourceFile   GetPoint];
  953.             [destFile   WriteReal:  numerator->x / denominator->x ]; // numerator
  954.             [destFile   WriteReal:  numerator->y / denominator->y ]; // numerator
  955.             FreeByteString((ByteString) numerator);
  956.             FreeByteString((ByteString) denominator);
  957.             [self WritePSProcedureName: "txRatio" ];
  958.             break;            
  959.         case 0x11 : // Version opcode
  960.             //
  961.             //    We should actually never end up here, I think, because the initial version
  962.             //    opcode is read in when the pict file opens.
  963.             //
  964.             buffer = NewCString(31);
  965.             [destFile WriteCommentUsing: buffer
  966.                 WithFormat: "PictVersion %d", [sourceFile   GetByte]];
  967.             FreeCString(buffer);
  968.             break;
  969.         case 0x12 : // Background patten (color)
  970.             UsedPatterns = YES;
  971.             [self ConvertPict2Pattern];
  972.             [self WritePSProcedureName: "bkPixPat"];
  973.              break;
  974.         case 0x13 : // Color pen pattern
  975.             UsedPatterns = YES;
  976.             [self ConvertPict2Pattern];
  977.             [self WritePSProcedureName: "pnPixPat"];
  978.              break;
  979.         case 0x14 : // color fill pattern
  980.             UsedPatterns = YES;
  981.             [self ConvertPict2Pattern];
  982.             [self WritePSProcedureName: "fillPixPat"];
  983.              break;
  984.         case 0x15 : // 'fractional pen position'
  985.             UsedMiscellaneous = YES;
  986.             [destFile   WriteInteger:  [sourceFile GetINTEGER]]; // the param... (pos?  neg??)
  987.             [self   WritePSProcedureName: "pnLocHFrac"];
  988.              break;
  989.         case 0x16 : // extra for each non-space character
  990.             UsedText = YES;
  991.             //
  992.             //    Dunno what this does. for sure.  IM suggested param is in a
  993.             //    special format...
  994.             //
  995.             [destFile   WriteInteger:  [sourceFile GetINTEGER]]; // the param...
  996.             [self WritePSProcedureName: "chExtra"];
  997.              break;
  998.         case 0x017:    // Several 'reserved for Apple use'
  999.         case 0x018:
  1000.         case 0x019:
  1001.             break;
  1002.         case 0x1A : // RGB foreground color 
  1003.             UsedColors = YES;
  1004.             [self ConvertRGBColor];
  1005.             [self WritePSProcedureName: "RGBFgCol"];
  1006.              break;
  1007.         case 0x1B : // RGB background color
  1008.             UsedColors = YES;
  1009.             [self ConvertRGBColor];
  1010.             [self WritePSProcedureName: "RGBBkCol"];
  1011.              break;
  1012.         case 0x1C : // Use hilite mode flag
  1013.             UsedMiscellaneous = YES;
  1014.             [self WritePSProcedureName: "hiliteMode"];
  1015.              break;
  1016.         case 0x1D : // RGB highlighting color
  1017.             UsedColors = YES;
  1018.             [self ConvertRGBColor];
  1019.             [self WritePSProcedureName: "hiliteColor"];
  1020.              break;
  1021.         case 0x1E : // Use default hilite color
  1022.             UsedColors = YES;
  1023.             [self WritePSProcedureName: "defHilite"];
  1024.              break;
  1025.         case 0x1F : // RGB OpColor for 'arithmetic modes'
  1026.             UsedColors = YES;
  1027.             [self ConvertRGBColor];
  1028.             [self WritePSProcedureName: "hiliteColor"];
  1029.              break;
  1030.         case 0xFF: // End of picture
  1031.             //
  1032.             //    Inside Mac (V5 P102) says 2 bytes follow this. Pict.r for MPW doesn't agree.
  1033.             //    I'm ignoring IMV5.  Can't imagine what they are..
  1034.             //    (This routine is defined in the common code, so I don't set a Use* flag here)
  1035.             //
  1036.             error = YES;    // hacked way to get out...
  1037.             [self   WritePSProcedureName: "endPict"];
  1038.             break;
  1039.         case 0x0C00: // Header op
  1040.             //
  1041.             //    93.08.15    djb    Turns out that Inside Mac 6 redefined the HeaderOp's
  1042.             //                contents.  So, we try to distinguish between the two and
  1043.             //                write them out appropriately between []'s because of the
  1044.             //                variable number of parameters.
  1045.             //                Note that theoretically IVM volume V said all args were -1
  1046.             //
  1047.             // (uses common)
  1048.             //
  1049.             [destFile  WriteText: "[ "];
  1050.             version = [sourceFile GetINTEGER];
  1051.             if (version == -2)    // As defined by IM volume 6
  1052.             {
  1053.                 [destFile   WriteInteger: version];
  1054.                 [destFile   WriteInteger: [sourceFile GetINTEGER]]; // reserved
  1055.                 buffer = NewCString(63);
  1056.                 [destFile   WriteTextUsing: buffer
  1057.                     WithFormat: "%.9f ", [sourceFile GetFixedNumber]];  // hres
  1058.                 [destFile   WriteTextUsing: buffer
  1059.                     WithFormat: "%.9f ", [sourceFile GetFixedNumber]];  // vres
  1060.                 FreeCString(buffer);
  1061.                 [destFile   WriteText: "[ "];
  1062.                 [self   WriteRect: [sourceFile GetRect]]; // source rectangle
  1063.                 [destFile   WriteText: "] "];
  1064.                 [destFile   WriteInteger: [sourceFile GetLONGINT]]; // reserved
  1065.             }
  1066.             else
  1067.             {
  1068.                 //
  1069.                 //    We must reconstruct the first longint.  ick.  Is my logic good?
  1070.                 //
  1071.                 temp2 = [sourceFile GetINTEGER];
  1072.                 tempsize = version << 16;
  1073.                 tempsize |= temp2;
  1074.                 [destFile   WriteInteger: tempsize];
  1075.                 [destFile   WriteInteger: [sourceFile GetLONGINT]];
  1076.                 [destFile   WriteInteger: [sourceFile GetLONGINT]];
  1077.                 [destFile   WriteInteger: [sourceFile GetLONGINT]];
  1078.                 [destFile   WriteInteger: [sourceFile GetLONGINT]];
  1079.                 [destFile   WriteInteger: [sourceFile GetLONGINT]];
  1080.             }
  1081.             [destFile   WriteText: "] "];
  1082.             [self   WritePSProcedureName: "headerOp"];
  1083.             break;
  1084.         default:
  1085.             error = YES;
  1086.             break;
  1087.     }
  1088.     return error;
  1089. }
  1090.  
  1091.  
  1092.  
  1093. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1094. //    Method:        ParseLineOpcode:
  1095. //    Parameters:
  1096. //        A PICT opcode code
  1097. //    Returns:     true if anything goes wrong
  1098. //    Stores:        none  explicitly (subcalls may)
  1099. //    Description:
  1100. //        This is one segment of the giant switch that parses pict opcodes.
  1101. //        This one deals with all the opcodes that draw lines.
  1102. //    Bugs:
  1103. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1104. - (Boolean) ParseLineOpcode: (PICTOpcode) opcode
  1105. {
  1106.     Boolean    error    = NO;
  1107.     //
  1108.     //    Set the type flag
  1109.     //
  1110.     UsedLines = YES;
  1111.     
  1112.     //
  1113.     //    Process the opcode
  1114.     //
  1115.     switch (opcode)
  1116.     {
  1117.         case 0x020:
  1118.             [self   WritePoint: [sourceFile   GetPoint] ]; // From
  1119.             [self   WritePoint: [sourceFile   GetPoint] ]; // To 
  1120.             [self   WritePSProcedureName: "line"];
  1121.              break;
  1122.         case 0x021: // Starts from 'current' point?
  1123.             [self   WritePoint: [sourceFile   GetPoint] ]; // To
  1124.             [self   WritePSProcedureName: "lineFrom"];
  1125.              break;
  1126.         case 0x022:    //point to dh,dv
  1127.             [self   WritePoint: [sourceFile   GetPoint] ]; // From
  1128.             [destFile   WriteInteger:  [sourceFile  GetSignedByte] ]; // dh
  1129.             [destFile   WriteInteger:  [sourceFile  GetSignedByte] ]; // dv
  1130.             [self   WritePSProcedureName: "shortLine"];
  1131.              break;
  1132.         case 0x023:
  1133.             [destFile   WriteInteger:  [sourceFile  GetSignedByte] ]; // dh
  1134.             [destFile   WriteInteger:  [sourceFile  GetSignedByte] ]; // dv
  1135.             [self   WritePSProcedureName: "shortLineFrom"];
  1136.              break;
  1137.         case 0x024:    // Several 'reserved for Apple use'
  1138.         case 0x025:
  1139.         case 0x026:
  1140.         case 0x027:
  1141.             [self   Skip2PlusData];
  1142.             break;
  1143.         default:
  1144.             error = YES;
  1145.             break;
  1146.     }
  1147.     return error;
  1148. }
  1149.  
  1150.  
  1151. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1152. //    Method:        ParseTextOpcode:
  1153. //    Parameters:
  1154. //        A PICT opcode code
  1155. //    Returns:     true if anything goes wrong
  1156. //    Stores:        none  explicitly (subcalls may)
  1157. //    Description:
  1158. //        This is one segment of the giant switch that parses pict opcodes.
  1159. //        This one deals with all the opcodes that deal with text.
  1160. //    History:
  1161. //        93.08.16    djb    Added 0x2C code.
  1162. //        93.08.18    djb    Added 0x2D opcode
  1163. //    Bugs:
  1164. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1165. - (Boolean) ParseTextOpcode: (PICTOpcode) opcode
  1166. {
  1167.     Boolean    error        = NO;
  1168.     CString    fontName;
  1169.     CString    newName;
  1170.     CString    buffer;
  1171.     //
  1172.     //    Set the type flag
  1173.     //
  1174.     UsedText = YES;
  1175.     
  1176.     //
  1177.     //    Process the opcode
  1178.     //
  1179.     switch (opcode)
  1180.     {
  1181.         case 0x028:
  1182.             [self   WritePoint: [sourceFile   GetPoint] ]; // From
  1183.             [self   WriteString: [sourceFile GetPString] ];
  1184.             [self   WritePSProcedureName: "longText" ];
  1185.              break;
  1186.         case 0x029:
  1187.             [destFile   WriteInteger:  [sourceFile  GetByte] ]; // dh
  1188.             [self   WriteString: [sourceFile GetPString] ];
  1189.             [self   WritePSProcedureName: "DHText" ];
  1190.              break;
  1191.         case 0x02A:
  1192.             [destFile   WriteInteger:  [sourceFile  GetByte] ]; // dv
  1193.             [self   WriteString: [sourceFile GetPString] ];
  1194.             [self   WritePSProcedureName: "DVText"];
  1195.              break;
  1196.         case 0x02B:
  1197.             [destFile   WriteInteger:  [sourceFile  GetByte] ]; // dh
  1198.             [destFile   WriteInteger:  [sourceFile  GetByte] ]; // dv
  1199.             [self   WriteString: [sourceFile GetPString] ];
  1200.             [self   WritePSProcedureName: "DHDVText" ];
  1201.              break;
  1202.         case 0x02C:
  1203.             [sourceFile  GetINTEGER];
  1204.             [sourceFile  GetINTEGER];
  1205.             fontName = [sourceFile GetPString];
  1206.             //
  1207.             //    Convert type family names
  1208.             //
  1209.             newName = NullCString;
  1210.             if (strcmp(fontName, "Times") == 0)
  1211.                 newName = "Times-Roman";
  1212.             else if (strcmp(fontName, "Avant Garde") == 0)
  1213.                 newName = "AvantGarde-Book";
  1214.             else if (strcmp(fontName, "Bookman") == 0)
  1215.                 newName = "Bookman-Light";
  1216.             else if (strcmp(fontName, "Helvetica Narrow") == 0)
  1217.                 newName = "Helvetica-Narrow";
  1218.             else if (strcmp(fontName, "New Century Schlbk") == 0)
  1219.                 newName = "NewCenturySchlbk-Roman";
  1220.             else if (strcmp(fontName, "Palatino") == 0)
  1221.                 newName = "Palatino-Roman";
  1222.             else if (strcmp(fontName, "Zapf Chancery") == 0)
  1223.                 newName = "ZapfChancery-MediumItalic";
  1224.             else if (strcmp(fontName, "New York") == 0)
  1225.                 newName = "NewYork";
  1226.             else if (strcmp(fontName, "Los Angeles") == 0)
  1227.                 newName = "LosAngeles";
  1228.             else if (strcmp(fontName, "San Francisco") == 0)
  1229.                 newName = "SanFrancisco";
  1230.             if (newName != NullCString)
  1231.             {
  1232.                 FreeCString(fontName);
  1233.                 fontName = newName;
  1234.             }
  1235.             [destFile   WriteText:  "/"];
  1236.             [destFile   WriteText:  fontName];
  1237.             [self   WritePSProcedureName: " fontName" ];
  1238.             break;
  1239.         case 0x02D:
  1240.             [sourceFile  GetINTEGER];    // Skip the length.  We don't care.
  1241.             buffer = NewCString(63);
  1242.             [destFile   WriteTextUsing: buffer
  1243.                 WithFormat: "%.9f ", [sourceFile GetFixedNumber]];  // intercharacter spacing
  1244.             [destFile   WriteTextUsing: buffer
  1245.                 WithFormat: "%.9f ", [sourceFile GetFixedNumber]];  // total extra space for justification
  1246.             FreeCString(buffer);
  1247.             [self   WritePSProcedureName: "lineJustify" ];
  1248.              break;
  1249.         case 0x02E:    // Several 'reserved for Apple use'
  1250.         case 0x02F:
  1251.             [self   Skip2PlusData];
  1252.             break;
  1253.         default:
  1254.             error = YES;
  1255.             break;
  1256.     }
  1257.     return error;
  1258. }
  1259.  
  1260.  
  1261.  
  1262. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1263. //    Method:        ParseRectangleOpcode:
  1264. //    Parameters:
  1265. //        A PICT opcode code
  1266. //    Returns:     true if anything goes wrong
  1267. //    Stores:        none  explicitly (subcalls may)
  1268. //    Description:
  1269. //        This is one segment of the giant switch that parses pict opcodes.
  1270. //        This one deals with all the opcodes that deal with Rectangles.
  1271. //    Bugs:
  1272. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1273. - (Boolean) ParseRectangleOpcode: (PICTOpcode) opcode
  1274. {
  1275.     Boolean    error    = NO;
  1276.     //
  1277.     //    Set the type flag
  1278.     //
  1279.     UsedRectangles = YES;
  1280.     
  1281.     //
  1282.     //    Process the opcode
  1283.     //
  1284.     switch (opcode)
  1285.     {
  1286.         case 0x30 : // frameRect . 
  1287.             [self   WriteRect: [sourceFile   GetRect] ];
  1288.             [self   WritePSProcedureName: "frameRect"];
  1289.              break;
  1290.         case 0x31 : // paintRect .
  1291.             [self   WriteRect: [sourceFile   GetRect] ];
  1292.             [self   WritePSProcedureName: "paintRect"];
  1293.              break;
  1294.         case 0x32 : // eraseRect . 
  1295.             [self   WriteRect: [sourceFile   GetRect] ];
  1296.             [self   WritePSProcedureName: "eraseRect"];
  1297.              break;
  1298.         case 0x33 : // invertRect .  
  1299.             [self   WriteRect: [sourceFile   GetRect] ];
  1300.             [self   WritePSProcedureName: "invertRect"];
  1301.              break;
  1302.         case 0x34 : // fillRect 
  1303.             [self   WriteRect: [sourceFile   GetRect] ];
  1304.             [self   WritePSProcedureName: "fillRect"];
  1305.              break;
  1306.         case 0x035:    // Several 'reserved for Apple use'  each require 8 bytes
  1307.         case 0x036:
  1308.         case 0x037:
  1309.             [sourceFile   AdvanceBytes: 8];
  1310.             break;
  1311.         case 0x38 : // frame same Rect 
  1312.             [self   WritePSProcedureName: "frameSameRect"];
  1313.              break;
  1314.         case 0x39 : // paint same Rect
  1315.             [self   WritePSProcedureName: "paintSameRect"];
  1316.              break;
  1317.         case 0x3A : // erase same Rect
  1318.             [self   WritePSProcedureName: "eraseSameRect"];
  1319.              break;
  1320.         case 0x3B : // invert same Rect
  1321.             [self   WritePSProcedureName: "invertSameRect"];
  1322.              break;
  1323.         case 0x3C : // fill same Rect
  1324.             [self   WritePSProcedureName: "fillSameRect"];
  1325.              break;
  1326.         case 0x03D:    // Several 'reserved for Apple use'.  Each takes no bytes of parameters.
  1327.         case 0x03E:
  1328.         case 0x03F:
  1329.             break;
  1330.         default:
  1331.             error = YES;
  1332.             break;
  1333.     }
  1334.     return error;
  1335. }
  1336.  
  1337.  
  1338. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1339. //    Method:        ParseRoundRectangleOpcode:
  1340. //    Parameters:
  1341. //        A PICT opcode code
  1342. //    Returns:     true if anything goes wrong
  1343. //    Stores:        none  explicitly (subcalls may)
  1344. //    Description:
  1345. //        This is one segment of the giant switch that parses pict opcodes.
  1346. //        This one deals with all the opcodes that deal with Rectangles.
  1347. //    Bugs:
  1348. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1349. - (Boolean) ParseRoundRectangleOpcode: (PICTOpcode) opcode
  1350. {
  1351.     Boolean    error    = NO;
  1352.     //
  1353.     //    Set the type flag
  1354.     //
  1355.     UsedRoundRectangles = YES;
  1356.     
  1357.     //
  1358.     //    Process the opcode
  1359.     //
  1360.     switch (opcode)
  1361.     {
  1362.         case 0x40 : // frameRRect
  1363.             [self   WriteRect: [sourceFile   GetRect] ];
  1364.             [self   WritePSProcedureName: "frameRRect"];
  1365.              break;
  1366.         case 0x41 : // paintRRec
  1367.             [self   WriteRect: [sourceFile   GetRect] ];
  1368.             [self   WritePSProcedureName: "paintRRect"];
  1369.              break;
  1370.         case 0x42 : // eraseRRect
  1371.             [self   WriteRect: [sourceFile   GetRect] ];
  1372.             [self   WritePSProcedureName: "eraseRRect"];
  1373.              break;
  1374.         case 0x43 : // invertRRect 
  1375.             [self   WriteRect: [sourceFile   GetRect] ];
  1376.             [self   WritePSProcedureName: "invertRRect"];
  1377.              break;
  1378.         case 0x44 : // fillRRect 
  1379.             [self   WriteRect: [sourceFile   GetRect] ];
  1380.             [self   WritePSProcedureName: "fillRRect"];
  1381.              break;
  1382.         case 0x045:    // Several 'reserved for Apple use'  each require 8 bytes
  1383.         case 0x046:
  1384.         case 0x047:
  1385.             [sourceFile   AdvanceBytes: 8];
  1386.             break;
  1387.         case 0x48 : // frame same RRect 
  1388.             [self   WritePSProcedureName: "frameSameRRect"];
  1389.              break;
  1390.         case 0x49 : // paint same RRect
  1391.             [self   WritePSProcedureName: "paintSameRRect"];
  1392.              break;
  1393.         case 0x4A : // erase same RRect
  1394.             [self   WritePSProcedureName: "eraseSameRRect"];
  1395.              break;
  1396.         case 0x4B : // invert same RRect
  1397.             [self   WritePSProcedureName: "invertSameRRect"];
  1398.              break;
  1399.         case 0x4C : // fill same RRect
  1400.             [self   WritePSProcedureName: "fillSameRRect"];
  1401.              break;
  1402.         case 0x04D:    // Several 'reserved for Apple use'.  Each takes no bytes of parameters.
  1403.         case 0x04E:
  1404.         case 0x04F:
  1405.             break;
  1406.         default:
  1407.             error = YES;
  1408.             break;
  1409.     }
  1410.     return error;
  1411. }
  1412.  
  1413.  
  1414. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1415. //    Method:        ParseOvalOpcode:
  1416. //    Parameters:
  1417. //        A PICT opcode code
  1418. //    Returns:     true if anything goes wrong
  1419. //    Stores:        none  explicitly (subcalls may)
  1420. //    Description:
  1421. //        This is one segment of the giant switch that parses pict opcodes.
  1422. //        This one deals with all the opcodes that deal with Ovals.
  1423. //    Bugs:
  1424. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1425. - (Boolean) ParseOvalOpcode: (PICTOpcode) opcode
  1426. {
  1427.     Boolean    error    = NO;
  1428.     //
  1429.     //    Set the type flag
  1430.     //
  1431.     UsedOvals = YES;
  1432.     
  1433.     //
  1434.     //    Process the opcode
  1435.     //
  1436.     switch (opcode)
  1437.     {
  1438.         case 0x50 : // frameOval 
  1439.             [self   WriteRect: [sourceFile   GetRect] ];
  1440.             [self   WritePSProcedureName: "frameOval"];
  1441.              break;
  1442.         case 0x51 : // paintOval
  1443.             [self   WriteRect: [sourceFile   GetRect] ];
  1444.             [self   WritePSProcedureName: "paintOval"];
  1445.              break;
  1446.         case 0x52 : // eraseOval 
  1447.             [self   WriteRect: [sourceFile   GetRect] ];
  1448.             [self   WritePSProcedureName: "eraseOval"];
  1449.              break;
  1450.         case 0x53 : // invertOval
  1451.             [self   WriteRect: [sourceFile   GetRect] ];
  1452.             [self   WritePSProcedureName: "invertOval"];
  1453.              break;
  1454.         case 0x54 : // fillOval
  1455.             [self   WriteRect: [sourceFile   GetRect] ];
  1456.             [self   WritePSProcedureName: "fillOval"];
  1457.              break;
  1458.         case 0x055:    // Several 'reserved for Apple use'  each require 8 bytes
  1459.         case 0x056:
  1460.         case 0x057:
  1461.             [sourceFile   AdvanceBytes: 8];
  1462.             break;
  1463.         case 0x58 : // frame same Oval 
  1464.             [self   WritePSProcedureName: "frameSameOval"];
  1465.              break;
  1466.         case 0x59 : // paint same Oval
  1467.             [self   WritePSProcedureName: "paintSameOval"];
  1468.              break;
  1469.         case 0x5A : // erase same Oval
  1470.             [self   WritePSProcedureName: "eraseSameOval"];
  1471.              break;
  1472.         case 0x5B : // invert same Oval
  1473.             [self   WritePSProcedureName: "invertSameOval"];
  1474.              break;
  1475.         case 0x5C : // fill same Oval
  1476.             [self   WritePSProcedureName: "fillSameOval"];
  1477.              break;
  1478.         case 0x05D:    // Several 'reserved for Apple use'.  Each takes no bytes of parameters.
  1479.         case 0x05E:
  1480.         case 0x05F:
  1481.             break;
  1482.         default:
  1483.             error = YES;
  1484.             break;
  1485.     }
  1486.     return error;
  1487. }
  1488.  
  1489.  
  1490.  
  1491. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1492. //    Method:        ParseArcOpcode:
  1493. //    Parameters:
  1494. //        A PICT opcode code
  1495. //    Returns:     true if anything goes wrong
  1496. //    Stores:        none  explicitly (subcalls may)
  1497. //    Description:
  1498. //        This is one segment of the giant switch that parses pict opcodes.
  1499. //        This one deals with all the opcodes that deal with Arcs.
  1500. //    Bugs:
  1501. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1502. - (Boolean) ParseArcOpcode: (PICTOpcode) opcode
  1503. {
  1504.     Boolean    error    = NO;
  1505.     //
  1506.     //    Set the type flag
  1507.     //
  1508.     UsedArcs = YES;
  1509.     
  1510.     //
  1511.     //    Process the opcode
  1512.     //
  1513.     switch (opcode)
  1514.     {
  1515.         case 0x60 : // frameArc 
  1516.             [self ConvertArc];
  1517.             [self   WritePSProcedureName: "frameArc" ];
  1518.              break;
  1519.         case 0x61 : // paintArc
  1520.             [self ConvertArc];
  1521.             [self   WritePSProcedureName: "paintArc" ];
  1522.              break;
  1523.         case 0x62 : // eraseArc 
  1524.             [self ConvertArc];
  1525.             [self   WritePSProcedureName: "eraseArc" ];
  1526.              break;
  1527.         case 0x63 : // invertArc .
  1528.             [self ConvertArc];
  1529.             [self   WritePSProcedureName: "invertArc" ];
  1530.              break;
  1531.         case 0x64 : // fillArc 
  1532.             [self ConvertArc];
  1533.             [self   WritePSProcedureName: "fillArc" ];
  1534.              break;
  1535.         case 0x065:    // Several 'reserved for Apple use'  each require 12 bytes
  1536.         case 0x066:
  1537.         case 0x067:
  1538.             [sourceFile AdvanceBytes: 12];
  1539.             break;
  1540.         //
  1541.         // The following 5 opcodes take angle measurements, but no rect        //
  1542.         case 0x68 : // frame same Arc 
  1543.             [self ConvertAngles];
  1544.             [self   WritePSProcedureName: "frameSameArc" ];
  1545.              break;
  1546.         case 0x69 : // paint same Arc
  1547.             [self ConvertAngles];
  1548.             [self   WritePSProcedureName: "paintSameArc" ];
  1549.              break;
  1550.         case 0x6A : // erase same Arc
  1551.             [self ConvertAngles];
  1552.             [self   WritePSProcedureName: "eraseSameArc" ];
  1553.              break;
  1554.         case 0x6B : // invert same Arc
  1555.             [self ConvertAngles];
  1556.             [self   WritePSProcedureName: "invertSameArc" ];
  1557.              break;
  1558.         case 0x6C : // fill same Arc
  1559.             [self ConvertAngles];
  1560.             [self   WritePSProcedureName: "fillSameArc" ];
  1561.              break;
  1562.         case 0x06D:    // Several 'reserved for Apple use'
  1563.         case 0x06E:
  1564.         case 0x06F:
  1565.             [sourceFile   AdvanceBytes: 4];
  1566.             break;
  1567.         default:
  1568.             error = YES;
  1569.             break;
  1570.     }
  1571.     return error;
  1572. }
  1573.  
  1574.  
  1575. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1576. //    Method:        ParsePolygonOpcode:
  1577. //    Parameters:
  1578. //        A PICT opcode code
  1579. //    Returns:     true if anything goes wrong
  1580. //    Stores:        none  explicitly (subcalls may)
  1581. //    Description:
  1582. //        This is one segment of the giant switch that parses pict opcodes.
  1583. //        This one deals with all the opcodes that deal with Polygon.
  1584. //    Bugs:
  1585. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1586. - (Boolean) ParsePolygonOpcode: (PICTOpcode) opcode
  1587. {
  1588.     Boolean    error    = NO;
  1589.     //
  1590.     //    Set the type flag
  1591.     //
  1592.     UsedPolygons = YES;
  1593.     UsedLines = YES;    // A cheat because we know that a routine in the Lines file is one we need
  1594.     
  1595.     //
  1596.     //    Process the opcode
  1597.     //
  1598.     switch (opcode)
  1599.     {
  1600.         case 0x70 : // framePoly .  
  1601.             [self ConvertPolygon];
  1602.             [self   WritePSProcedureName: "framePoly"];
  1603.              break;
  1604.         case 0x71 : // paintPoly .  .  
  1605.             [self ConvertPolygon];
  1606.             [self   WritePSProcedureName: "paintPoly"];
  1607.              break;
  1608.         case 0x72 : // erasePoly .  .  
  1609.             [self ConvertPolygon];
  1610.             [self   WritePSProcedureName: "erasePoly"];
  1611.              break;
  1612.         case 0x73 : // invertPoly .  .  
  1613.             [self ConvertPolygon];
  1614.             [self   WritePSProcedureName: "invertPoly"];
  1615.              break;
  1616.         case 0x74 : // fillPoly .  .  
  1617.             [self ConvertPolygon];
  1618.             [self   WritePSProcedureName: "fillPoly"];
  1619.              break;
  1620.         case 0x075:    // Several 'reserved for Apple use'  All are followed by a Polygon
  1621.         case 0x076:
  1622.         case 0x077:
  1623.             [self   SkipSizedObject];
  1624.             break;
  1625.         case 0x78 : // frame same Poly (not yet actually implemented by apple) 
  1626.             [self   WritePSProcedureName: "frameSamePoly" ];
  1627.              break;
  1628.         case 0x79 : // paint same Poly (not yet actually implemented by apple) 
  1629.             [self   WritePSProcedureName: "paintSamePoly" ];
  1630.              break;
  1631.         case 0x7A : // erase same Poly (not yet actually implemented by apple) 
  1632.             [self   WritePSProcedureName: "eraseSamePoly" ];
  1633.              break;
  1634.         case 0x7B : // invert same Poly (not yet actually implemented by apple) 
  1635.             [self   WritePSProcedureName: "invertSamePoly" ];
  1636.              break;
  1637.         case 0x7C : // fill same Poly (not yet actually implemented by apple) 
  1638.             [self   WritePSProcedureName: "fillSamePoly" ];
  1639.              break;
  1640.         case 0x07D:    // Several 'reserved for Apple use'  None have data bytes
  1641.         case 0x07E:
  1642.         case 0x07F:
  1643.             break;
  1644.         default:
  1645.             error = YES;
  1646.             break;
  1647.     }
  1648.     return error;
  1649. }
  1650.  
  1651.  
  1652. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1653. //    Method:        ParseRegionOpcode:
  1654. //    Parameters:
  1655. //        A PICT opcode code
  1656. //    Returns:     true if anything goes wrong
  1657. //    Stores:        none  explicitly (subcalls may)
  1658. //    Description:
  1659. //        This is one segment of the giant switch that parses pict opcodes.
  1660. //        This one deals with all the opcodes that deal with Regions.
  1661. //    Bugs:
  1662. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1663. - (Boolean) ParseRegionOpcode: (PICTOpcode) opcode
  1664. {
  1665.     Boolean    error    = NO;
  1666.     //
  1667.     //    Set the type flag
  1668.     //
  1669.     UsedRegions = YES;
  1670.     
  1671.     //
  1672.     //    Process the opcode
  1673.     //
  1674.     switch (opcode)
  1675.     {
  1676.         case 0x80 : // frameRgn
  1677.             [self ConvertRegion];
  1678.             [self   WritePSProcedureName: "frameRgn"];
  1679.              break;
  1680.         case 0x81 : // paintRgn
  1681.             [self ConvertRegion];
  1682.             [self   WritePSProcedureName: "paintRgn"];
  1683.              break;
  1684.         case 0x82 : // eraseRgn
  1685.             [self ConvertRegion];
  1686.             [self   WritePSProcedureName: "eraseRgn"];
  1687.              break;
  1688.         case 0x83 : // invertRgn
  1689.             [self ConvertRegion];
  1690.             [self   WritePSProcedureName: "invertRgn"];
  1691.              break;
  1692.         case 0x84 : // fillRgn
  1693.             [self ConvertRegion];
  1694.             [self   WritePSProcedureName: "fillRgn"];
  1695.              break;
  1696.         case 0x085:    // Several 'reserved for Apple use'  All are followed by a region 
  1697.         case 0x086:
  1698.         case 0x087:
  1699.             [self SkipSizedObject];
  1700.             break;
  1701.         case 0x88 : // frame same rgn (not yet actually implemented by apple) 
  1702.             [self   WritePSProcedureName: "frameSameRgn" ];
  1703.              break;
  1704.         case 0x89 : // paint same rgn (not yet actually implemented by apple) 
  1705.             [self   WritePSProcedureName: "paintSameRgn" ];
  1706.              break;
  1707.         case 0x8A : // erase same rgn (not yet actually implemented by apple) 
  1708.             [self   WritePSProcedureName: "eraseSameRgn" ];
  1709.              break;
  1710.         case 0x8B : // invert same rgn (not yet actually implemented by apple) 
  1711.             [self   WritePSProcedureName: "invertSameRgn" ];
  1712.              break;
  1713.         case 0x8C : // fill same rgn (not yet actually implemented by apple) 
  1714.             [self   WritePSProcedureName: "fillSameRgn" ];
  1715.              break;
  1716.         case 0x08D:    // Several 'reserved for Apple use'  None have data bytes
  1717.         case 0x08E:
  1718.         case 0x08F:
  1719.             break;
  1720.         default:
  1721.             error = YES;
  1722.             break;
  1723.     }
  1724.     return error;
  1725. }
  1726.  
  1727.  
  1728. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1729. //    Method:        ParseBitmapOpcode:
  1730. //    Parameters:
  1731. //        A PICT opcode code
  1732. //    Returns:     true if anything goes wrong
  1733. //    Stores:        none  explicitly (subcalls may)
  1734. //    Description:
  1735. //        This is one segment of the giant switch that parses pict opcodes.
  1736. //        This one deals with all the opcodes that deal with Bitmaps.
  1737. //    History:
  1738. //        93.08.21    djb    Added branches for the direct bitmaps 9a and 9b
  1739. //                    Added a crude error code returning capability.
  1740. //    Bugs:
  1741. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1742. - (Boolean) ParseBitmapOpcode: (PICTOpcode) opcode
  1743. {
  1744.     Boolean    error    = NO;
  1745.     //
  1746.     //    Set the type flag
  1747.     //
  1748.     UsedBitmaps = YES;
  1749.     
  1750.     //
  1751.     //    Process the opcode
  1752.     //
  1753.     switch (opcode)
  1754.     {
  1755.         case 0x90 :
  1756.             [self   ConvertBitmapWithRegion: NO PackedData: NO];
  1757.              break;
  1758.         case 0x91 :
  1759.             [self   ConvertBitmapWithRegion: YES  PackedData: NO];
  1760.              break;
  1761.         case 0x092:    // Several 'reserved for Apple use'
  1762.         case 0x093:
  1763.         case 0x094:
  1764.         case 0x095:
  1765.         case 0x096:
  1766.         case 0x097:
  1767.             [self   Skip2PlusData];
  1768.             break;
  1769.         case 0x98 :
  1770.             [self   ConvertBitmapWithRegion: NO PackedData: YES];
  1771.              break;
  1772.         case 0x99 :
  1773.             [self   ConvertBitmapWithRegion: YES  PackedData: YES];
  1774.              break;
  1775.         case 0x09A:
  1776.             [self   ConvertDirectBitmapWithRegion: NO];
  1777.             break;
  1778.         case 0x09B:
  1779.             [self   ConvertDirectBitmapWithRegion: YES];
  1780.             break;
  1781.         case 0x09C:    // Several 'reserved for Apple use'
  1782.         case 0x09D:
  1783.         case 0x09E:
  1784.         case 0x09F:
  1785.             [self   Skip2PlusData];
  1786.             break;
  1787.         default:
  1788.             error = YES;
  1789.             break;
  1790.     }
  1791.     
  1792.     if ([self   GetErrorCode] < ERR_OK)
  1793.     {
  1794.         error = YES;
  1795.     }
  1796.     return error;
  1797. }
  1798.  
  1799.  
  1800. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1801. //    Method:        ParseCommentOpcode:
  1802. //    Parameters:
  1803. //        A PICT opcode code
  1804. //    Returns:     true if anything goes wrong
  1805. //    Stores:        none  explicitly (subcalls may)
  1806. //    Description:
  1807. //        This routine process the two picture comment opcodes.  One opcode's data is merely
  1808. //        a number indicating it's 'kind'.  The other opcode's data is a kind and a length of
  1809. //        data.  It happens that there are lots of opcodes out there, and many of them don't
  1810. //        seem to be documented, meaning they're basically proprietary.  There used to be
  1811. //        a publicly defined set that MacDraw used, but that info is now Claris', and isn't
  1812. //        as redily available.  So, what this routine does is it will do what little processing it
  1813. //        can for the opcodes defined in the TechNotes or Inside Mac #1, and for the others
  1814. //        write them out in a generic form.  That is, Inside Mac or TN ones will be written out
  1815. //        in the form:
  1816. //            [args] /name longComment
  1817. //        While unknown ones will be written out as
  1818. //            <hex-data> kind longComment
  1819. //        (short comments the same, without args or hex-data).
  1820. //        Note these points: the kind and args have reversed position from earlier versions
  1821. //        of the converter.  Our arguments are different types depending on what we know
  1822. //        about them. Also, the appspecific one will go out as a hex string and with a name.
  1823. //        Naturally, if the user has asked to remove all pic comments, nothing is written out.
  1824. //        †    These comments are obsolete.
  1825. //        #    These comments are not recommended.
  1826. //    History:
  1827. //        93.07.18    Started doing some Picture comment stuff (added kinds 0, 1)
  1828. //    Bugs:
  1829. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1830. - (Boolean) ParseCommentOpcode: (PICTOpcode) opcode
  1831. {
  1832.     Boolean    error    = NO;
  1833.     CString    buffer    = NewCString(1024);
  1834.     PositiveInteger    kind;
  1835.     PositiveInteger    length;
  1836.     CString            tempString;
  1837.     TPolyVerbRec    polyBitfield;
  1838.     Byte            tempByte;
  1839.     SignedByte        tempSignedByte;
  1840.     SignedByte        numIntervals;
  1841.     PositiveInteger    index;
  1842.  
  1843.     kind = [sourceFile GetPositiveINTEGER];
  1844.  
  1845.     if (PicCommentOperation == DiscardPicComments)
  1846.     {
  1847.         if (opcode == 0xA1)
  1848.             [self   Skip2PlusData];
  1849.     }
  1850.     else
  1851.     {
  1852.         UsedComments = YES;
  1853.  
  1854.         if (opcode == 0xA0)
  1855.             [self   ParseShortComment: kind];
  1856.         else
  1857.         {
  1858.             length = [sourceFile GetPositiveINTEGER];
  1859.             switch (kind)
  1860.             {
  1861.                 case 100:
  1862.                     [self   ConvertHexBytes: length];
  1863.                     //
  1864.                     //    Extract copies of MYAP, and 2 byte number?
  1865.                     //
  1866.                     [destFile   WriteText: "/AppComment "];
  1867.                     break;
  1868.                 case 150:    //Begin text function
  1869.                     if (length != 10)
  1870.                     {
  1871.                         //
  1872.                         //    Doc gives conflicting sizes.  if it's not the one we want do generic.
  1873.                         //
  1874.                         [destFile  WriteCommentUsing: buffer
  1875.                             WithFormat: "%s (%d)", 
  1876.                             "WARNING: Unexpected datalength for TextBegin.  doing nothing!",
  1877.                             length];
  1878.                         [self   ConvertHexBytes: length];
  1879.                         [destFile   WritePositiveInteger: kind];
  1880.                     }
  1881.                     else
  1882.                     {
  1883.                         UsedText = YES;
  1884.                         [destFile   WriteText: "[ "];
  1885.                         //
  1886.                         //    Read tJus
  1887.                         //
  1888.                         tempByte = [sourceFile   GetByte];
  1889.                         switch (tempByte)
  1890.                         {
  1891.                             case tJusNone:
  1892.                                 [destFile   WriteText: "/tJusNone "];
  1893.                                 break;
  1894.                             case tJusLeft:
  1895.                                 [destFile   WriteText: "/tJusLeft "];
  1896.                                 break;
  1897.                             case tJusCenter:
  1898.                                 [destFile   WriteText: "/tJusCenter "];
  1899.                                 break;
  1900.                             case tJusRight:
  1901.                                 [destFile   WriteText: "/tJusRight "];
  1902.                                 break;
  1903.                             case tJusFull:
  1904.                                 [destFile   WriteText: "/tJusFull "];
  1905.                                 break;
  1906.                         }
  1907.                         //
  1908.                         //    Read tFlip
  1909.                         //
  1910.                         tempByte = [sourceFile   GetByte];
  1911.                         switch (tempByte)
  1912.                         {
  1913.                             case tFlipNone:
  1914.                                 [destFile   WriteText: "/tFlipNone "];
  1915.                                 break;
  1916.                             case tFlipHorizontal:
  1917.                                 [destFile   WriteText: "/tFlipHorizontal "];
  1918.                                 break;
  1919.                             case tFlipVertical:
  1920.                                 [destFile   WriteText: "/tFlipVertical "];
  1921.                                 break;
  1922.                         }
  1923.                         //
  1924.                         //    tAngle  (clockwise rotation in degrees 0..360)
  1925.                         //
  1926.                         [destFile  WriteInteger: [sourceFile GetINTEGER]];
  1927.                         //
  1928.                         //    Skip these unused and reserved bytes (tLine and tCmnt)
  1929.                         //
  1930.                         [sourceFile   GetByte];
  1931.                         [sourceFile   GetByte];
  1932.                         //
  1933.                         //    tAngleFixed (same as "tAngle" in Fixed precision)
  1934.                         //
  1935.                         [destFile   WriteTextUsing: buffer
  1936.                             WithFormat: "%.9f ", [sourceFile GetFixedNumber]];
  1937.                         [destFile   WriteText: "]"];
  1938.                         [destFile   WriteText: " /TextBegin "];
  1939.                     }
  1940.                     break;
  1941.                 case 154:    //Offset to center of rotation
  1942.                     [destFile   WriteText: "[ "];
  1943.                     [destFile   WriteTextUsing: buffer
  1944.                         WithFormat: "%.9f ", [sourceFile GetFixedNumber]];
  1945.                     [destFile   WriteTextUsing: buffer
  1946.                         WithFormat: "%.9f ", [sourceFile GetFixedNumber]];
  1947.                     [destFile   WriteText: "]"];
  1948.                     [destFile   WriteText: " /TextCenter "];
  1949.                     break;
  1950.                 case 157:    //Customize line layout error distribution #
  1951.                     [destFile   WriteText: "[ "];
  1952.                     //
  1953.                     //    Parameters are, respecitvely, 
  1954.                     //        chCount    Apply for so many characters.
  1955.                     //        major    percentage of line layout error to be distributed
  1956.                     //                among space characters.
  1957.                     //        spcChar    code of character that is to absorb
  1958.                     //                the "major" line layout error
  1959.                     //        minor    percentage of intercharacter distrib.
  1960.                     //        ulLength    underline length.
  1961.                     //
  1962.                     [destFile  WriteInteger: [sourceFile GetINTEGER]]; // Apply this # chars
  1963.                     [destFile   WriteTextUsing: buffer
  1964.                         WithFormat: "%.9f ", [sourceFile GetFixedNumber]];
  1965.                     [destFile  WriteInteger: [sourceFile GetINTEGER]];
  1966.                     [destFile   WriteTextUsing: buffer
  1967.                         WithFormat: "%.9f ", [sourceFile GetFixedNumber]];
  1968.                     [destFile   WriteTextUsing: buffer
  1969.                         WithFormat: "%.9f ", [sourceFile GetFixedNumber]];
  1970.                     [destFile   WriteText: "]"];
  1971.                     [destFile   WriteText: " /ClientLineLayout "];
  1972.                     break;
  1973.                 case 164:    //Close, Fill, Frame
  1974.                     //
  1975.                     //    Hey.  Since we only care about 3 of the fields, we could probably
  1976.                     //    just read this in as a byte, and look for the values from 0 to 8 (or the
  1977.                     //    reverse if the byte is reversed).  Just a thought.
  1978.                     //
  1979.                     polyBitfield = [sourceFile GetPolyVerbs];
  1980.                     [destFile   WriteText: "[ "];
  1981.                     if (polyBitfield.fPolyClose  == YES)
  1982.                         [destFile   WriteText: "/Close "];
  1983.                     if (polyBitfield.fPolyFill  == YES)
  1984.                         [destFile   WriteText: "/Fill "];
  1985.                     if (polyBitfield.fPolyFrame  == YES)
  1986.                         [destFile   WriteText: "/Frame "];
  1987.                     [destFile   WriteText: "]"];
  1988.                     [destFile   WriteText: " /PolySmooth "];
  1989.                     break;
  1990.                 case 180:    //Draw following lines as dashed
  1991.                     tempSignedByte = (SignedByte) [sourceFile   GetByte];
  1992.                     [destFile   WriteText: "[ "];
  1993.                     [destFile  WriteInteger: tempSignedByte];
  1994.                     //
  1995.                     //    Skip the centered argument
  1996.                     //
  1997.                     [sourceFile   GetByte];
  1998.                     //
  1999.                     //    Write out the dash info, unless our length is way wrong
  2000.                     //
  2001.                     numIntervals =  (SignedByte) [sourceFile   GetByte];
  2002.                     if ((numIntervals + 3) != length)
  2003.                     {
  2004.                         [destFile  WriteCommentUsing: buffer
  2005.                             WithFormat: "%s (%d expected %d)", 
  2006.                             "WARNING: Unexpected datalength for DashedLine.  doing nothing!",
  2007.                             length,
  2008.                             numIntervals+3];
  2009.                         [destFile  WriteInteger: numIntervals];
  2010.                         [self   ConvertHexBytes: length-3];
  2011.                         [destFile   WriteText: "]"];
  2012.                         [destFile   WritePositiveInteger: kind];
  2013.                     }
  2014.                     else
  2015.                     {
  2016.                         //
  2017.                         //    All is well, so write out the offset and dash info.
  2018.                         //        (put this info in additional braces for easier processing.
  2019.                         //
  2020.                         [destFile   WriteText: " [ "];
  2021.                         for (index = 1; index <= numIntervals; index++)
  2022.                         {
  2023.                             tempSignedByte = (SignedByte) [sourceFile   GetByte];
  2024.                             [destFile  WriteInteger: tempSignedByte];
  2025.                         }
  2026.                         [destFile   WriteText: "]"];
  2027.  
  2028.                         [destFile   WriteText: " ]"];
  2029.                         [destFile   WriteText: " /DashedLine "];
  2030.                     }
  2031.                     break;
  2032.                 case 182:    // Set fractional line widths
  2033.                     //
  2034.                     //    the arguments are v/h which become a fraction to scale the pen in both
  2035.                     //    dimensions by.
  2036.                     //    Output:   v h div
  2037.                     //
  2038.                     [destFile  WriteInteger: [sourceFile GetINTEGER]];
  2039.                     [destFile  WriteInteger: [sourceFile GetINTEGER]];
  2040.                     [destFile   WriteText: " div "];
  2041.                     [destFile   WriteText: "/SetLineWidth "];
  2042.                     break;
  2043.                 case 192:    // PostScript data in handle
  2044.                     tempString = NewCString(length);
  2045.                     [sourceFile  Read: length BytesInto: tempString];
  2046.                     tempString[length] = 0;
  2047.                     [self   WriteString: tempString];
  2048.                     [destFile   WriteText: " /PostScriptHandle "];
  2049.                     FreeCString(tempString);
  2050.                     break;
  2051.                 case 193:    // FileName in data handle †
  2052.                     tempString = NewCString(length);
  2053.                     [sourceFile  Read: length BytesInto: tempString];
  2054.                     tempString[length] = 0;
  2055.                     [self   WriteString: tempString];
  2056.                     [destFile   WriteText: " /PostScriptFile "];
  2057.                     FreeCString(tempString);
  2058.                     break;
  2059.                 case 195:    // PostScript data in a resource †
  2060.                     //
  2061.                     //    Should be doing some length error checking?
  2062.                     //
  2063.                     [destFile  WriteComment: "WARNING: The ResourcePS values are quite possibly wrong."];
  2064.                     [destFile   WriteText: "[ "];
  2065.                     //
  2066.                     //    Read in the type
  2067.                     //
  2068.                     tempString = NewCString(4);
  2069.                     [sourceFile  Read: 4 BytesInto: tempString];
  2070.                     tempString[4] = 0;    //93.11.06    Fixed.  Was setting tempString[length] to 0, but length is 8 in this case.  oops.
  2071.                     [self   WriteString: tempString];
  2072.                     //
  2073.                     //    Convert the ID and Index
  2074.                     //
  2075.                     [destFile  WriteInteger: [sourceFile GetINTEGER]];
  2076.                     [destFile  WriteInteger: [sourceFile GetINTEGER]];
  2077.                     [destFile   WriteText: "]"];
  2078.                     [destFile   WriteText: " /ResourcePS "];
  2079.                     FreeCString(tempString);
  2080.                     break;
  2081.                 case 197:    // Call PostScript's setgray operator #
  2082.                     [destFile   WriteTextUsing: buffer
  2083.                         WithFormat: "%.9f ", [sourceFile GetFixedNumber]];
  2084.                     [destFile   WriteText: " /SetGrayLevel "];
  2085.                     break;
  2086.                 case 200:    //Begin rotated port
  2087.                     if (length != 8)
  2088.                     {
  2089.                         [destFile  WriteCommentUsing: buffer
  2090.                             WithFormat: "%s (%d)", 
  2091.                             "WARNING: Unexpected datalength for RotateBegin.  doing nothing!",
  2092.                             length];
  2093.                         [self   ConvertHexBytes: length];
  2094.                         [destFile   WritePositiveInteger: kind];
  2095.                     }
  2096.                     else
  2097.                     {
  2098.                         [destFile   WriteText: "[ "];
  2099.                         [destFile  WriteInteger: [sourceFile GetINTEGER]];  //flip
  2100.                         [destFile  WriteInteger: [sourceFile GetINTEGER]];  //angle
  2101.                         [destFile   WriteTextUsing: buffer
  2102.                             WithFormat: "%.9f ", [sourceFile GetFixedNumber]];  //fixed angle
  2103.                         [destFile   WriteText: "]"];
  2104.                         [destFile   WriteText: " /RotateBegin "];
  2105.                     }
  2106.                     break;
  2107.                 case 202:    //Offset to center of rotation
  2108.                     [destFile   WriteText: "[ "];
  2109.                     [destFile   WriteTextUsing: buffer
  2110.                         WithFormat: "%.9f ", [sourceFile GetFixedNumber]];
  2111.                     [destFile   WriteTextUsing: buffer
  2112.                         WithFormat: "%.9f ", [sourceFile GetFixedNumber]];
  2113.                     [destFile   WriteText: "]"];
  2114.                     [destFile   WriteText: " /RotateCenter "];
  2115.                     break;
  2116.                 default:
  2117.                     //    read in a length, then that # bytes and hex out.
  2118.                     [self   ConvertHexBytes: length];
  2119.                     [destFile   WritePositiveInteger: kind];
  2120.                     break;
  2121.             }
  2122.             [self   WritePSProcedureName: "longComment"];
  2123.         }
  2124.     }
  2125.     FreeCString(buffer);
  2126.     return error;
  2127. }
  2128.  
  2129.  
  2130. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2131. //    Method:        ParseShortComment:
  2132. //    Parameters:
  2133. //        A kind of short comment
  2134. //    Returns:     self
  2135. //    Stores:        none  explicitly (subcalls may)
  2136. //    Description:
  2137. //        This routine process short pict comments.  At the moment, this merely means
  2138. //        writing out a name or a number for the specified kind of short comment.  Names
  2139. //        are written out when we know what about this kind of comment, numbers are
  2140. //        written out otherwise.
  2141. //        †    These comments are obsolete.
  2142. //        #    These comments are not recommended.
  2143. //    History:
  2144. //        93.08.01    Split off from the PicComment conversion code.
  2145. //    Bugs:
  2146. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2147. - ParseShortComment: (Integer) kind
  2148. {
  2149.     switch (kind)
  2150.     {
  2151.         //
  2152.         //    Defined in Inside Mac V 1
  2153.         //
  2154.         case 0:
  2155.             [destFile   WriteText: "/picLParen "];
  2156.             break;
  2157.         case 1:
  2158.             [destFile   WriteText: "/picRParen "];
  2159.             break;
  2160.         //
  2161.         //    Mentioned in Tech note as being ImageWriter specific
  2162.         //
  2163.         case 1000:
  2164.             [destFile   WriteText: "/BitMapThinningOff "];
  2165.             break;
  2166.         case 1001:
  2167.             [destFile   WriteText: "/BitMapThinningOn "];
  2168.             break;
  2169.         //
  2170.         //    Mainly LaserWriter/PS specific.  Defined in Tech Note
  2171.         //
  2172.         case 151:        // End text function
  2173.             [destFile   WriteText: "/TextEnd "];
  2174.             break;
  2175.         case 152:        // Begin string delimitation
  2176.             [destFile   WriteText: "/StringBegin "];
  2177.             break;
  2178.         case 153:        // End string delimitation
  2179.             [destFile   WriteText: "/StringEnd "];
  2180.             break;
  2181.         case 155:        // Turn LaserWriter line layout off
  2182.             [destFile   WriteText: "/LineLayoutOff "];
  2183.             break;
  2184.         case 156:        // Turn LaserWriter line layout on
  2185.             [destFile   WriteText: "/LineLayoutOn "];
  2186.             break;
  2187.         case 160:        // Begin special polygon
  2188.             [destFile   WriteText: "/PolyBegin "];
  2189.             break;
  2190.         case 161:        // End special polygon
  2191.             [destFile   WriteText: "/PolyEnd "];
  2192.             break;
  2193.         case 163:        // Ignore following polygon data
  2194.             [destFile   WriteText: "/PolyIgnore "];
  2195.             break;
  2196.         case 165:        // Close the polygon
  2197.             [destFile   WriteText: "/PolyClose "];
  2198.             break;
  2199.         case 181:        // End dashed lines
  2200.             [destFile   WriteText: "/DashedStop "];
  2201.             break;
  2202.         case 190:        //Set driver state to PostScript
  2203.             [destFile   WriteText: "/PostScriptBegin "];
  2204.             break;
  2205.         case 191:        //Restore QuickDraw state
  2206.             [destFile   WriteText: "/PostScriptEnd "];
  2207.             break;
  2208.         case 194:        //QuickDraw text is sent as PostScript †
  2209.             UsedText = YES;
  2210.             [destFile   WriteText: "/TextIsPostScript "];
  2211.             break;
  2212.         case 196:        //Set driver state to PostScript
  2213.             [destFile   WriteText: "/PSBeginNoSave "];
  2214.             break;
  2215.         case 201:        //End rotation
  2216.             [destFile   WriteText: "/RotateEnd "];
  2217.             break;
  2218.         case 210:        //Don't clear print buffer after each page #
  2219.             [destFile   WriteText: "/FormsPrinting "];
  2220.             break;
  2221.         case 211:        // End forms printing after PrClosePage #
  2222.             [destFile   WriteText: "/EndFormsPrinting "];
  2223.             break;
  2224.         default:
  2225.             [destFile   WritePositiveInteger: kind];
  2226.             break;
  2227.     }
  2228.     [self   WritePSProcedureName: "shortComment"];
  2229.     return self;
  2230. }
  2231.  
  2232.  
  2233.  
  2234. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2235. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2236. //                    PROCESSING UTILITIES
  2237. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2238. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2239.  
  2240. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2241. //    Method:        Skip2PlusData:
  2242. //    Parameters:    none
  2243. //    Returns:     self
  2244. //    Stores:        none  explicitly (subcalls may)
  2245. //    Description:
  2246. //        This reads a 16 bit number in, and then moves forward as many bytes as
  2247. //        that specifies in the source file.  This is usefull because if we run into an unknown
  2248. //        opcode, it may be of the form 2 bytes of size, and that many bytes of data, and this
  2249. //        allows us to skip over it gracefully. 
  2250. //    Bugs:
  2251. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2252. - Skip2PlusData
  2253. {
  2254.     PositiveInteger    numBytes;
  2255.  
  2256.     numBytes = [sourceFile   GetPositiveINTEGER];
  2257.     [sourceFile   AdvanceBytes: numBytes];
  2258.     return self;
  2259. }
  2260.  
  2261.  
  2262. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2263. //    Method:        Skip4PlusData:
  2264. //    Parameters:    none
  2265. //    Returns:     self
  2266. //    Stores:        none  explicitly (subcalls may)
  2267. //    Description:
  2268. //        This reads a 32 bit number in, and then moves forward as many bytes as
  2269. //        that specifies.  Useful for the same reason as Skip2PlusData:;
  2270. //    Bugs:
  2271. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2272. - Skip4PlusData
  2273. {
  2274.     PositiveInteger    numBytes;
  2275.  
  2276.     numBytes = [sourceFile   GetPositiveLONGINT];
  2277.     [sourceFile   AdvanceBytes: numBytes];
  2278.     return self;
  2279. }
  2280.  
  2281. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2282. //    Method:        SkipSizedObject:
  2283. //    Parameters:    none
  2284. //    Returns:     self
  2285. //    Stores:        none  explicitly (subcalls may)
  2286. //    Description:
  2287. //        Read in a size value (2 bytes), and use it's value to skip over all that many remaining
  2288. //        bytes.  This differs from Skip2PlusData in that the byte count is part of the number
  2289. //        of bytes we are skipping. 
  2290. //    Bugs:
  2291. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2292. - SkipSizedObject
  2293. {
  2294.     PositiveInteger    size;
  2295.     
  2296.     size = [sourceFile   GetPositiveINTEGER];
  2297.     [sourceFile   AdvanceBytes: size-2];
  2298.     return self;
  2299. }
  2300.  
  2301. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2302. //    Method:        ConvertHexBytes:
  2303. //    Parameters:    The number of bytes to convert.
  2304. //    Returns:     self
  2305. //    Stores:        none  explicitly (subcalls may)
  2306. //    Description:
  2307. //        read the specified number of bytes from the source file, and write them out as hex
  2308. //        digits in the eps file.  use a slow brute force algorithm.  =)
  2309. //    Bugs:
  2310. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2311. - ConvertHexBytes: (PositiveInteger) theBytes
  2312. {
  2313.     PositiveInteger    byteCounter;
  2314.     CString            buffer    = NewCString(2);
  2315.     
  2316.     [destFile   WriteText: "<"];
  2317.     
  2318.     for (byteCounter = 0; byteCounter < theBytes; byteCounter++)
  2319.         [destFile   WriteTextUsing: buffer WithFormat: "%.2X",  (Byte)[sourceFile GetByte]];
  2320.  
  2321.     [destFile   WriteText: "> "];
  2322.     FreeCString(buffer);
  2323.     return self;
  2324. }
  2325.  
  2326.  
  2327.  
  2328. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2329. //    Method:        WritePoint:
  2330. //    Parameters:
  2331. //        A Point structure
  2332. //    Returns:     self
  2333. //    Stores:        none  explicitly (subcalls may)
  2334. //    Description:
  2335. //        This simply writes out the pict's x and y coordinates, and then it assumes it
  2336. //        may free the point structure, since that's how it's always used. =)
  2337. //    Bugs:
  2338. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2339. - WritePoint: (PICTPoint*) thePoint
  2340. {
  2341.     [destFile   WriteInteger: thePoint->x];
  2342.     [destFile   WriteInteger: thePoint->y];
  2343.     
  2344.     FreeByteString( (ByteString) thePoint);
  2345.     return self;
  2346. }
  2347.  
  2348.  
  2349. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2350. //    Method:        WriteRect:
  2351. //    Parameters:
  2352. //        A Rect structure
  2353. //    Returns:     self
  2354. //    Stores:        none  explicitly (subcalls may)
  2355. //    Description:
  2356. //        This simply writes out the rectangle, and then it assumes it
  2357. //        may free the rectangle structure, since that's how it's always used.  =)
  2358. //    Bugs:
  2359. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2360. - WriteRect: (PICTRect*) theRect
  2361. {
  2362.     [destFile   WriteInteger: theRect->top];
  2363.     [destFile   WriteInteger: theRect->left];
  2364.     [destFile   WriteInteger:  theRect->bottom ];
  2365.     [destFile   WriteInteger:  theRect->right];
  2366.  
  2367.     FreeByteString((ByteString)theRect);
  2368.     return self;
  2369. }
  2370.  
  2371.  
  2372. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2373. //    Method:        WritePSProcedureName:
  2374. //    Parameters:
  2375. //        A CString
  2376. //    Returns:     self
  2377. //    Stores:        none  explicitly (subcalls may)
  2378. //    Description:
  2379. //        This merely writes a procedure name that we are passed, and follows it
  2380. //        with a newline.  Any time we are writing one of our procedure names, it'll
  2381. //        be the last thing on a line, so, we hard-code this behavior.
  2382. //    Bugs:
  2383. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2384. - WritePSProcedureName: (CString) theName
  2385. {
  2386.     [destFile   WriteText: theName];
  2387.     [destFile   WriteText: "\n"];
  2388.     return self;
  2389. }
  2390.  
  2391.  
  2392. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2393. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2394. //                PRIMARY DATA CONVERSION ROUTINES
  2395. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2396. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2397.  
  2398. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2399. //    Method:        ConvertAngles:
  2400. //    Parameters:    none
  2401. //    Returns:     self
  2402. //    Stores:        none  explicitly (subcalls may)
  2403. //    Description:
  2404. //        This reads the information about the angles of a pict arc in from the current position
  2405. //        in the source file, and then converts the information to a form that can be used
  2406. //        easily in the resulting postscript file
  2407. //        The angles for a PICT arc is stored as an initial angle, and the number of degrees from
  2408. //        the start angle to the end of the arc.  We write it out as a start angle and a finish
  2409. //        angle.
  2410. //    Bugs:
  2411. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2412. - ConvertAngles
  2413. {
  2414.     Integer    startAng,
  2415.             deltaAng,
  2416.             finishAng;
  2417.     //
  2418.     //    Read in angles, and compensate for the different position of 0deg in PICT and PS.
  2419.     //    then, compute the finish position, given the start and the delta.
  2420.     //
  2421.     startAng =  [sourceFile   GetINTEGER];
  2422.     deltaAng = [sourceFile GetINTEGER];
  2423.     startAng -= 90;    // compensate for the fact that PICT 90 is PS 0  (I think))
  2424.     
  2425.     if (deltaAng > 0)
  2426.         finishAng = startAng + deltaAng;
  2427.     else
  2428.     {
  2429.         finishAng = startAng;
  2430.         startAng = finishAng + deltaAng;
  2431.     }
  2432.     //
  2433.     //    To make things prettier, check if the numbers are negative, and if so, add 360.
  2434.     //    no promises that they will not still be negative afterwards.  but most of the time they
  2435.     //    will, and this will make the code easier to understand
  2436.     //    @@ Is there a chance that these will write out misleading numbers?  That is, it used
  2437.     //    to say go from x to x+y.  now we say, go from x to z, but can we end up somehow with
  2438.     //    z being behind x when it shouldn't?
  2439.     //
  2440.     if (startAng < 0)
  2441.         startAng += 360;
  2442.     if (finishAng < 0)
  2443.         finishAng += 360;
  2444.     
  2445.     [destFile   WriteInteger: startAng];
  2446.     [destFile   WriteInteger: finishAng];
  2447.     
  2448.     return self;
  2449. }
  2450.  
  2451.  
  2452. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2453. //    Method:        ConvertArc:
  2454. //    Parameters:    none
  2455. //    Returns:     self
  2456. //    Stores:        none  explicitly (subcalls may)
  2457. //    Description:
  2458. //        This reads the information about an arc in from the current position in the
  2459. //        source file, and then converts the information to a form that can be used
  2460. //        easily in the resulting postscript file
  2461. //        A PICT arc is stored as a bounding rectangle, which defines overall size and
  2462. //        overall circle-ness/ovalness of the circle/oval we are drawing the arc in.  After
  2463. //        this rectangle, the start and finish angles of the arc are stored.
  2464. //    Bugs:
  2465. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2466. - ConvertArc
  2467. {
  2468.     [self   WriteRect: [sourceFile   GetRect] ];
  2469.     [self   ConvertAngles];
  2470.     return self;
  2471. }
  2472.  
  2473.  
  2474.  
  2475. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2476. //    Method:        ConvertPolygon:
  2477. //    Parameters:
  2478. //    Returns:     self
  2479. //    Stores:        none  explicitly (subcalls may)
  2480. //    Description:
  2481. //        A Mac polygon consists of the following: 2 bytes of size, 8 bytes of bounding rect,
  2482. //        and a sequence of points that describe the vertices (including start and end points) of
  2483. //        a polygon.  Note that a polygon need not be a closed object.   This takes said object, and
  2484. //        writes out the points of the polygon as a series of numbers, these are followed by the
  2485. //        number of poits that we have written and finally the bounding rectangle is written
  2486. //    Bugs:
  2487. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2488.  
  2489. - ConvertPolygon
  2490. {
  2491.     PICTRect*    bounds;
  2492.     Integer        numPoints,
  2493.                 pointsOnLine = 0;
  2494.     Integer        RemainingPoints;
  2495.     PICTPoint*    thePoint;
  2496.     PositiveInteger    size;
  2497.     //
  2498.     //    Get the size, and the bounding rectangle, anc compute the number of vertices
  2499.     //    using the total size of the object
  2500.     //
  2501.     size = [sourceFile   GetPositiveINTEGER];
  2502.     bounds = [sourceFile   GetRect];
  2503.     numPoints = 0;
  2504.     RemainingPoints = (size-10) / 4;
  2505.     //
  2506.     //    For each vertex, write out a little PS array of the form [x y].  Don't put more than
  2507.     //    8 on a line so things will remain readable for any browsing humans.
  2508.     //
  2509.     thePoint = [sourceFile   GetPoint];
  2510.     RemainingPoints--;
  2511.     while ( RemainingPoints >= 0 )
  2512.     {
  2513.         numPoints++;
  2514.         [destFile   WriteText: "["];
  2515.         [self   WritePoint: thePoint];
  2516.         [destFile   WriteText: "]"];
  2517.         if (pointsOnLine == 8)
  2518.         {
  2519.             pointsOnLine = 0;
  2520.             [destFile   ForceNewLine];    
  2521.         }
  2522.         else
  2523.             pointsOnLine++;
  2524.             
  2525.         if (RemainingPoints > 0)
  2526.             thePoint = [sourceFile   GetPoint];
  2527.         RemainingPoints--;    // if it was 0, this will drop it below, which will fall out of the main loop
  2528.     }
  2529.     //
  2530.     //    Well.  That was easy.  Now, just write out the number of points, so the ps routine
  2531.     //    will be able to consume all the data properly, and write out the bounding rectangle
  2532.     //    
  2533.     [destFile   WriteInteger: numPoints];
  2534.     [self   WriteRect: bounds];
  2535.  
  2536.     return self;
  2537. }
  2538.  
  2539.  
  2540. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2541. //    Method:        ConvertRegion:
  2542. //    Parameters:    none
  2543. //    Returns:     self
  2544. //    Stores:        none  explicitly (subcalls may)
  2545. //    Description:
  2546. //        A Mac region is arranged like so: 2 bytes of size of the whole region, 8 bytes of
  2547. //        bounding rectangle, then N groups of data about segments of lins.  Each group
  2548. //        of segments has a y coordinate, and then a start and stop x coordinate for
  2549. //        each segment.  Anyway, this creates a converter instance, and asks it to
  2550. //        convert the region waiting in the source file, to the destination file. 
  2551. //    Bugs:
  2552. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2553. - ConvertRegion
  2554. {
  2555.     Instance regConverter;
  2556.     regConverter= [[regionConverter  alloc] init];
  2557.     [regConverter   ConvertRegionFrom: sourceFile To: destFile];
  2558.     [regConverter  free];
  2559.     return self;
  2560. }
  2561.  
  2562.  
  2563.  
  2564. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2565. //    Method:        ConvertMode
  2566. //    Parameters:    none
  2567. //    Returns:     self
  2568. //    Stores:        none  explicitly (subcalls may)
  2569. //    Description:
  2570. //        This takes a Mac mode type value, and writes out a PS name corresponding to it
  2571. //    History:
  2572. //        93.07.18    djb    added magicMode which is a mysterious pen mode defined in a tech note.
  2573. //                    It's effect is, it seems, to be to cause QuickDraw to process stuff, but not 
  2574. //                    actually draw anything.
  2575. //    Bugs:
  2576. //        This gets called by a routine which wants only src, and one that wants
  2577. //        only pat.  Because we do no checking of this, there's no way to keep us from
  2578. //        writing out an illegal mode for that routin.
  2579. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2580. - ConvertMode
  2581. {
  2582.     PositiveInteger    modeNum;
  2583.     CString            buffer;
  2584.     
  2585.     modeNum = [sourceFile   GetPositiveINTEGER];
  2586.     switch (modeNum)
  2587.     {
  2588.         case macSrcCopy:
  2589.             [destFile   WriteText: "/srcCopy "];
  2590.             break;
  2591.         case macSrcOr:
  2592.             [destFile   WriteText: "/srcOr "];
  2593.             break;
  2594.         case macSrcXor:
  2595.             [destFile   WriteText: "/srcXor "];
  2596.             break;
  2597.         case macSrcBic:
  2598.             [destFile   WriteText: "/srcBic "];
  2599.             break;
  2600.         case macNotSrcCopy:
  2601.             [destFile   WriteText: "/notSrcCopy "];
  2602.             break;
  2603.         case macNotSrcXor:
  2604.             [destFile   WriteText: "/notSrcXor "];
  2605.             break;
  2606.         case macNotSrcOr:
  2607.             [destFile   WriteText: "/notSrcOr "];
  2608.             break;
  2609.         case macNotSrcBic:
  2610.             [destFile   WriteText: "/notSrcBic "];
  2611.             break;
  2612.         case macPatCopy:
  2613.             [destFile   WriteText: "/patCopy "];
  2614.             break;
  2615.         case macPatOr:
  2616.             [destFile   WriteText: "/patOr "];
  2617.             break;
  2618.         case macPatXor:
  2619.             [destFile   WriteText: "/patXor "];
  2620.             break;
  2621.         case macPatBic:
  2622.             [destFile   WriteText: "/patBic "];
  2623.             break;
  2624.         case macNotPatCopy:
  2625.             [destFile   WriteText: "/notPatCopy "];
  2626.             break;
  2627.         case macNotPatOr:
  2628.             [destFile   WriteText: "/notPatOr "];
  2629.             break;
  2630.         case macNotPatXor:
  2631.             [destFile   WriteText: "/notPatXor "];
  2632.             break;
  2633.         case macNotPatBic:
  2634.             [destFile   WriteText: "/notPatBic "];
  2635.             break;
  2636.         case blend:
  2637.             [destFile   WriteText: "/blend "];
  2638.             break;
  2639.         case addPin:
  2640.             [destFile   WriteText: "/addPin "];
  2641.             break;
  2642.         case addOver:
  2643.             [destFile   WriteText: "/addOver "];
  2644.             break;
  2645.         case subPin:
  2646.             [destFile   WriteText: "/subPin "];
  2647.             break;
  2648.         case addMax:
  2649.             [destFile   WriteText: "/addMax "];
  2650.             break;
  2651.         case subOver:
  2652.             [destFile   WriteText: "/subOver "];
  2653.             break;
  2654.         case adMin:
  2655.             [destFile   WriteText: "/adMin "];
  2656.             break;
  2657.         case transparent:
  2658.             [destFile   WriteText: "/transparent "];
  2659.             break;
  2660.         case magicMode:
  2661.             [destFile   WriteText: "/magicMode "];
  2662.             break;
  2663.         default:
  2664.             buffer = NewCString(64);
  2665.             [destFile   WriteTextUsing: buffer
  2666.                 WithFormat: "/badMode%d ", modeNum];
  2667.             FreeCString(buffer);
  2668.             break;
  2669.     }
  2670.     return self;
  2671. }
  2672.  
  2673.  
  2674.  
  2675.  
  2676. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2677. //    Method:        ConvertFamily:
  2678. //    Parameters:    none
  2679. //    Returns:     self
  2680. //    Stores:        none  explicitly (subcalls may)
  2681. //    Description:
  2682. //        This reads a number in from the pict file.  from this number, we either write out the
  2683. //        name of a standard mac type face, or we write out a number.  We also set the
  2684. //        ConvertCurrentCharacters flag, which is used when writing out strings
  2685. //        from the text opcodes later.  If this is set to NO, then we will not attempt to
  2686. //        convert the text.  Otherwise we will.
  2687. //    Bugs:
  2688. //        I dunno whether this is really a positive or a signed integer.  No tests were done,
  2689. //        and no doc seems to indicate for sure.  
  2690. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2691.  
  2692. - ConvertFamily
  2693. {
  2694.     PositiveInteger    familyNum;
  2695.     
  2696.     familyNum = [sourceFile GetPositiveINTEGER];
  2697.     switch (familyNum)
  2698.     {
  2699.         case 0:
  2700.             [destFile   WriteText: "/Chicago "];
  2701.             ConvertCurrentCharacters = YES;
  2702.             break;
  2703.         case 2:
  2704.             [destFile   WriteText: "/NewYork "];
  2705.             ConvertCurrentCharacters = YES;
  2706.             break;
  2707.         case 3:
  2708.             [destFile   WriteText: "/Geneva "];
  2709.             ConvertCurrentCharacters = YES;
  2710.             break;
  2711.         case 4:
  2712.             [destFile   WriteText: "/Monaco "];
  2713.             ConvertCurrentCharacters = YES;
  2714.             break;
  2715.         case 5:
  2716.             [destFile   WriteText: "/Venice "];
  2717.             ConvertCurrentCharacters = YES;
  2718.             break;
  2719.         case 6:
  2720.             [destFile   WriteText: "/London "];
  2721.             ConvertCurrentCharacters = YES;
  2722.             break;
  2723.         case 7:
  2724.             [destFile   WriteText: "/Athens "];
  2725.             ConvertCurrentCharacters = YES;
  2726.             break;
  2727.         case 8:
  2728.             ConvertCurrentCharacters = YES;
  2729.             [destFile   WriteText: "/SanFrancisco "];
  2730.             break;
  2731.         case 9:
  2732.             [destFile   WriteText: "/Toronto "];
  2733.             ConvertCurrentCharacters = YES;
  2734.             break;
  2735.         case 10:
  2736.             [destFile   WriteText: "/Seattle "];
  2737.             ConvertCurrentCharacters = YES;
  2738.             break;
  2739.         case 11:
  2740.             [destFile   WriteText: "/Cairo "];
  2741.             ConvertCurrentCharacters = NO;
  2742.             break;
  2743.         case 12:
  2744.             [destFile   WriteText: "/LosAngeles "];
  2745.             ConvertCurrentCharacters = YES;
  2746.             break;
  2747.         case 13:
  2748.             [destFile   WriteText: "/ZapfDingbats "];
  2749.             ConvertCurrentCharacters = NO;
  2750.             break;
  2751.         case 14:
  2752.             [destFile   WriteText: "/Bookman-Light "];
  2753.             ConvertCurrentCharacters = YES;
  2754.             break;
  2755.         case 15:
  2756.             [destFile   WriteText: "/Helvetica-Narrow "];
  2757.             ConvertCurrentCharacters = YES;
  2758.             break;
  2759.         case 16:
  2760.             [destFile   WriteText: "/Palatino-Roman "];
  2761.             ConvertCurrentCharacters = YES;
  2762.             break;
  2763.         case 18:
  2764.             [destFile   WriteText: "/ZapfChancery-MediumItalic "];
  2765.             ConvertCurrentCharacters = YES;
  2766.             break;
  2767.         case 20:
  2768.             [destFile   WriteText: "/Times-Roman "];
  2769.             ConvertCurrentCharacters = YES;
  2770.             break;
  2771.         case 21:
  2772.             [destFile   WriteText: "/Helvetica "];
  2773.             ConvertCurrentCharacters = YES;
  2774.             break;
  2775.         case 22:
  2776.             [destFile   WriteText: "/Courier "];
  2777.             ConvertCurrentCharacters = YES;
  2778.             break;
  2779.         case 23:
  2780.             [destFile   WriteText: "/Symbol "];
  2781.             ConvertCurrentCharacters = NO;
  2782.             break;
  2783.         case 24:
  2784.             [destFile   WriteText: "/Mobile "]; // Also known as Taliesin
  2785.             ConvertCurrentCharacters = NO;
  2786.             break;
  2787.         case 33:
  2788.             [destFile   WriteText: "/AvantGarde-Book "];
  2789.             ConvertCurrentCharacters = YES;
  2790.             break;
  2791.         case 34:
  2792.             [destFile   WriteText: "/NewCenturySchlbk-Roman "];
  2793.             ConvertCurrentCharacters = YES;
  2794.             break;
  2795.         default:
  2796.             [destFile   WriteInteger: familyNum];
  2797.             ConvertCurrentCharacters = UsersCharConvertChoice;
  2798.             break;
  2799.     }
  2800.     return self;
  2801. }
  2802.  
  2803.  
  2804. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2805. //    Method:        ConvertFace:
  2806. //    Parameters:    none
  2807. //    Returns:     self
  2808. //    Stores:        none  explicitly (subcalls may)
  2809. //    Description:
  2810. //        This converts the byte of data describing typeface attributes and writes it
  2811. //        out as a PS array describing the various attributes.
  2812. //    Bugs:
  2813. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2814. - ConvertFace
  2815. {
  2816.     bits8    theFace;
  2817.     
  2818.     theFace = [sourceFile  GetByte];
  2819.     [destFile   WriteText:"\[ "];
  2820.     if (boldBit & theFace)
  2821.         [destFile   WriteText:"/bold "];
  2822.     if (italicBit & theFace)
  2823.         [destFile   WriteText:"/italic "];
  2824.     if (underlineBit & theFace)
  2825.         [destFile   WriteText:"/underline "];
  2826.     if (outlineBit & theFace)
  2827.         [destFile   WriteText:"/outline "];
  2828.     if (shadowBit & theFace)
  2829.         [destFile   WriteText:"/shadow "];
  2830.     if (condenseBit & theFace)
  2831.         [destFile   WriteText:"/condense "];
  2832.     if (extendBit & theFace)
  2833.         [destFile   WriteText:"/extend "];
  2834.     [destFile   WriteText:"] "];
  2835.     return self;
  2836. }
  2837.  
  2838.  
  2839.  
  2840. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2841. //    Method:        WriteString:
  2842. //    Parameters:    A CString structure
  2843. //    Returns:     self
  2844. //    Stores:        none  explicitly (subcalls may)
  2845. //    Description:
  2846. //        This simply writes out specified string as a PS string, in parens, follows it with
  2847. //        a space, and then free's the string.
  2848. //    Bugs:
  2849. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2850. - WriteString: (CString) theString
  2851. {
  2852.     CString    convertedString;
  2853.     CString    filteredString;
  2854.     CString    tempString;
  2855.     PositiveInteger    filterIndex;
  2856.     PositiveInteger    index;
  2857.     PositiveInteger    newLength = strlen(theString);
  2858.     
  2859.     if (ConvertCurrentCharacters == YES)
  2860.     {
  2861.         //
  2862.         //    Convert the Mac characters to the NeXT equivalents
  2863.         //    
  2864.         convertedString = [textConverter  ConvertString: theString
  2865.                 WithLength: strlen(theString)];
  2866.         newLength    = [textConverter   GetPositiveIntegerFrom: SECOND_RESULT];
  2867.         FreeCString(theString);
  2868.         theString = convertedString;
  2869.     }
  2870.     //
  2871.     //    Now, filter this string, replacing certain troublesome characters with
  2872.     //    escaped equivalents.
  2873.     //
  2874.     filteredString = NewCString(newLength*4); // worst case each all will become \ddd
  2875.     filterIndex = 0;
  2876.     for (index = 0; index < newLength; index++)
  2877.     {
  2878.         if ( (PositiveInteger) theString[index] < (PositiveInteger) ' ')
  2879.         {
  2880.             tempString = NewCString(4);
  2881.             //
  2882.             //    93.01.31    djb    OOPS!  Had been using %.3u, not octal!
  2883.             //
  2884.             sprintf(tempString, "\\%.3o", (unsigned int) theString[index]);
  2885.             strcat(filteredString, tempString);
  2886.             FreeCString(tempString);
  2887.             filterIndex += 4;
  2888.         }
  2889.         else
  2890.         {
  2891.             switch (theString[index])
  2892.             {
  2893.                 case '\\' :
  2894.                     strcat(filteredString, "\\\\");
  2895.                     filterIndex += 2;
  2896.                     break;
  2897.                 case '(' :
  2898.                     strcat(filteredString, "\\(");
  2899.                     filterIndex += 2;
  2900.                     break;
  2901.                 case ')' :
  2902.                     strcat(filteredString, "\\)");
  2903.                     filterIndex += 2;
  2904.                     break;
  2905.                 default :
  2906.                     filteredString[filterIndex] = theString[index];
  2907.                     filterIndex ++;
  2908.                     filteredString[filterIndex] = EndOfCString; // put a null back on.
  2909.                     break;
  2910.             }
  2911.         }
  2912.     
  2913.     }
  2914.     //
  2915.     //    write out the new string
  2916.     //
  2917.     [destFile   WriteText: "("];
  2918.     [destFile   WriteText: filteredString];
  2919.     [destFile   WriteText: ") "];
  2920.     
  2921.     FreeCString(filteredString);
  2922.     FreeCString(theString);
  2923.     return self;
  2924. }
  2925.  
  2926.  
  2927. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2928. //    Method:        ConvertOldColor
  2929. //    Parameters:    none.
  2930. //    Returns:     self
  2931. //    Stores:        none  explicitly (subcalls may)
  2932. //    Description:
  2933. //        This reads in a four byte old style Mac color, and writes it out as an array of
  2934. //        RGB values.  If the color isn't one of the pre-defined ones (in theory, this shouldn't
  2935. //        happen, I think), we instead write out an integer with the number of the color so
  2936. //        the PS code can perhaps deal with it.
  2937. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2938. - ConvertOldColor
  2939. {
  2940.     PositiveInteger    colorNum;
  2941.     
  2942.     colorNum = [sourceFile GetPositiveLONGINT];
  2943.     switch (colorNum)
  2944.     {
  2945.         case oldBlackColor:
  2946.             [destFile   WriteText: "[0 0 0] "];
  2947.             break;
  2948.         case oldWhiteColor:
  2949.             [destFile   WriteText: "[1 1 1] "];
  2950.             break;
  2951.         case oldRedColor:
  2952.             [destFile   WriteText: "[1 0 0] "];
  2953.             break;
  2954.         case oldGreenColor:
  2955.             [destFile   WriteText: "[0 1 0] "];
  2956.             break;
  2957.         case oldBlueColor:
  2958.             [destFile   WriteText: "[0 0 1] "];
  2959.             break;
  2960.         case oldCyanColor:
  2961.             [destFile   WriteText: "[0 1 1] "];
  2962.             break;
  2963.         case oldMagentaColor:
  2964.             [destFile   WriteText: "[1 0 1] "];
  2965.             break;
  2966.         case oldYellowColor:
  2967.             [destFile   WriteText: "[1 1 0] "];
  2968.             break;
  2969.         default:
  2970.             [destFile   WritePositiveInteger: colorNum];
  2971.             break;
  2972.     }
  2973.     return self;
  2974. }
  2975.  
  2976.  
  2977.  
  2978. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2979. //    Method:        ConvertRGBColor
  2980. //    Parameters:    none.
  2981. //    Returns:     self
  2982. //    Stores:        none  explicitly (subcalls may)
  2983. //    Description:
  2984. //        read a mac rgb value in, write out as an array of 3 numbers from 0 to 1 for PS
  2985. //    Bugs:
  2986. //        I really can't tell whether to treat these colors as 8 or 16 bit values.  I'm assuming
  2987. //        8 for the moment.  change maxMACCOLOR to 65535.0 if
  2988. //        it should be 16.  (read in with GetPositiveINTEGER)
  2989. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2990. #define maxMACCOLOR 255.0
  2991. - ConvertRGBColor
  2992. {
  2993.     CString    tempString = NewCString(12);
  2994.     [destFile   WriteText: "["];
  2995.     //
  2996.     //    Read the red component
  2997.     //
  2998.     [destFile   WriteTextUsing: tempString
  2999.         WithFormat: "%.9f ", ( [sourceFile   GetByte] / maxMACCOLOR)];
  3000.     [sourceFile  AdvanceBytes: 1];
  3001.     //
  3002.     //    Read the green component
  3003.     //
  3004.     [destFile   WriteTextUsing: tempString
  3005.         WithFormat: "%.9f ", ( [sourceFile   GetByte] / maxMACCOLOR)];
  3006.     [sourceFile  AdvanceBytes: 1];
  3007.     //
  3008.     //    Read the blue component
  3009.     //
  3010.     [destFile   WriteTextUsing: tempString
  3011.         WithFormat: "%.9f ", ( [sourceFile   GetByte] / maxMACCOLOR)];
  3012.     [sourceFile  AdvanceBytes: 1];
  3013.     [destFile   WriteText: "] "];
  3014.  
  3015.     FreeCString(tempString);
  3016.     return self;
  3017. }
  3018.  
  3019.  
  3020.  
  3021.  
  3022. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3023. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3024. //                    BITMAP AND PATTERN PROCESSING
  3025. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3026. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3027.  
  3028.  
  3029.  
  3030. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3031. //    Method:        ConvertInvertedHexBytes:
  3032. //    Parameters:    The number of bytes to convert.
  3033. //    Returns:     self
  3034. //    Stores:        none  explicitly (subcalls may)
  3035. //    Description:
  3036. //        read the specified number of bytes from the source file, and write them out as hex
  3037. //        digits in the eps file, inverting as we go.  use a slow brute force algorithm.  =)
  3038. //    Bugs:
  3039. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3040. - ConvertInvertedHexBytes: (PositiveInteger) theBytes
  3041. {
  3042.     PositiveInteger    byteCounter;
  3043.     CString            buffer    = NewCString(2);
  3044.     
  3045.     [destFile   WriteText: "<"];
  3046.     
  3047.     for (byteCounter = 0; byteCounter < theBytes; byteCounter++)
  3048.         [destFile   WriteTextUsing: buffer WithFormat: "%.2X",  (Byte) ~[sourceFile GetByte]];
  3049.  
  3050.     [destFile   WriteText: "> "];
  3051.     FreeCString(buffer);
  3052.     return self;
  3053. }
  3054.  
  3055.  
  3056. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3057. //    Method:        ConvertPict1Pattern
  3058. //    Parameters:    none.
  3059. //    Returns:     self
  3060. //    Stores:        none  explicitly (subcalls may)
  3061. //    Description:
  3062. //        This merely reads an 'old-style' 8 byte B&W pattern in from the pict file, and writes
  3063. //        it out as a binary string to the PS file.   We also write a type (0) of pattern
  3064. //        out so the parser can distinguish this from the other two types.
  3065. //    Bugs:
  3066. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3067. - ConvertPict1Pattern
  3068. {
  3069.     [self ConvertInvertedHexBytes: 8];
  3070.     [destFile   WritePositiveInteger: 0];
  3071.     return self;
  3072. }
  3073.  
  3074.  
  3075. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3076. //    Method:        GetPixMapFrom:
  3077. //    Parameters:    the file to read a Mac pixmap record structure from
  3078. //                A pixmap structure to read into.
  3079. //    Returns:     self
  3080. //    Stores:        none
  3081. //    Description:
  3082. //        This reads in a PixMap structure that was written out on a Macintosh.
  3083. //        Because it is from a Mac, it is made up of lots of big endian integers.  Because
  3084. //        we may be running on an Intel or other platform, we need to convert these
  3085. //        integers so they are of the right form for the native endianness.  We do this in
  3086. //        a brute force method: read in the mac form, create a second structure, and
  3087. //        effectively copy over all the fields, flipping the bytes if necessary as we go.
  3088. //    History:
  3089. //        93.08.01    djb    Created
  3090. //        93.08.15    djb    Argh!  I need to be casting the results!!!
  3091. //        93.08.16    djb    Argh! again! Wasn't casting properly in all cases.
  3092. //    Bugs:
  3093. //        I consider it icy design that we are being passed the structuer to fill in, and aren't
  3094. //        just returning on our own (the latter allows more flexibility).  However, this
  3095. //        routine was added long after it's callers were, and they were already depending on
  3096. //        their pixmaps structures being allocated on the stack.  I didn't want to risk changing
  3097. //        all the foo.bar's to foo->bar's.  So, this gets passed a map structure instead.  =(
  3098. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3099. - GetPixMapFrom: SourceFile  Into: (modPixMap*) nativeMap
  3100. {
  3101.     [sourceFile   Read:  sizeof(modPixMap)  BytesInto: (ByteString) nativeMap];
  3102.     //
  3103.     //    Now, swap all the fields of the pixmap structure from the mac format to whatever
  3104.     //    the native one is. .
  3105.     //
  3106.     nativeMap->bounds.top = (INTEGER)NXSwapBigShortToHost(nativeMap->bounds.top);
  3107.     nativeMap->bounds.right = (INTEGER)NXSwapBigShortToHost(nativeMap->bounds.right);
  3108.     nativeMap->bounds.bottom = (INTEGER)NXSwapBigShortToHost(nativeMap->bounds.bottom);
  3109.     nativeMap->bounds.left = (INTEGER)NXSwapBigShortToHost(nativeMap->bounds.left);
  3110.     nativeMap->pmVersion = (INTEGER)NXSwapBigShortToHost(nativeMap->pmVersion);
  3111.     nativeMap->packType = (INTEGER)NXSwapBigShortToHost(nativeMap->packType);
  3112.     nativeMap->packSize = (LONGINT)NXSwapBigLongToHost(nativeMap->packSize);
  3113.     nativeMap->hRes = (FIXED)NXSwapBigLongToHost(nativeMap->hRes);
  3114.     nativeMap->vRes = (FIXED)NXSwapBigLongToHost(nativeMap->vRes);
  3115.     nativeMap->pixelType = (INTEGER)NXSwapBigShortToHost(nativeMap->pixelType);
  3116.     nativeMap->pixelSize = (INTEGER)NXSwapBigShortToHost(nativeMap->pixelSize);
  3117.     nativeMap->cmpCount = (INTEGER)NXSwapBigShortToHost(nativeMap->cmpCount);
  3118.     nativeMap->cmpSize = (INTEGER)NXSwapBigShortToHost(nativeMap->cmpSize);
  3119.     nativeMap->planeBytes = (LONGINT)NXSwapBigLongToHost(nativeMap->planeBytes);
  3120.     nativeMap->pmTable = (LONGINT)NXSwapBigLongToHost(nativeMap->pmTable);
  3121.     nativeMap->pmReserved = (LONGINT)NXSwapBigLongToHost(nativeMap->pmReserved);
  3122.     //
  3123.     //    dispose of the source one, and return the destination.
  3124.     //
  3125. //    FreeByteString((ByteString)macMap);
  3126.     return self;
  3127. }
  3128.  
  3129.  
  3130. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3131. //    Method:        ConvertPict2Pattern
  3132. //    Parameters:    none.
  3133. //    Returns:     self
  3134. //    Stores:        none  explicitly (subcalls may)
  3135. //    Description:
  3136. //        This reads in a PICT 2 pattern, massages the data, and writes it out for the
  3137. //        PS file.  Inside Mac V. 5 only documents two types (1&2) on p. 103.
  3138. //        Type 2: 8byte B&W pattern, and RGB color.  IM V suggests that the pattern is
  3139. //            there only for things to use if they are on a B&W machine.  Because PS
  3140. //            can deal with a color, and I can see no reason why it should ever need the
  3141. //            pattern in this case, I am discarding this data!  This may be a mistake, though.
  3142. //        Type 1: 'arbitrary' bitmap used as pattern...
  3143. //    Bugs:
  3144. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3145. - ConvertPict2Pattern
  3146. {
  3147.     PositiveInteger    patType;
  3148.     PICTRect*        bounds    = (PICTRect*)NewByteString(sizeof(PICTRect));
  3149.     modPixMap        theMap;
  3150.     PositiveInteger    dataHigh, dataWide;
  3151.     PositiveInteger    rowBytes;
  3152.     Integer            bitsDeep;
  3153.     Real                hScale, vScale;
  3154.     CString            tempString    = NewCString(30);
  3155.     Boolean            isPacked;
  3156.     Boolean            tempPacking;
  3157.     
  3158.  
  3159.     patType = [sourceFile   GetPositiveINTEGER];
  3160.     [self ConvertInvertedHexBytes: 8];
  3161.     switch (patType)
  3162.     {
  3163.         case 1 :
  3164.             //
  3165.             //    Clear the high bit of rowBytes, read in the pixmap data, and convert
  3166.             //    the color table that follows it. (same basic flow of events as in the bitmap
  3167.             //    converter below.
  3168.             //
  3169.             rowBytes =0x7FFF &  [sourceFile   GetPositiveINTEGER];
  3170.             [self   GetPixMapFrom: sourceFile  Into: &theMap];
  3171.             [self  ConvertColorTable];
  3172.             //
  3173.             //    move the rectangle bounding data into the bounds rect..
  3174.             //
  3175.             bounds->left = theMap.bounds.left;
  3176.             bounds->top = theMap.bounds.top;
  3177.             bounds->bottom = theMap.bounds.bottom;
  3178.             bounds->right = theMap.bounds.right;
  3179.             bitsDeep = theMap.pixelSize;
  3180.             [destFile   WriteInteger: bitsDeep];
  3181.             dataHigh = bounds->bottom - bounds->top;
  3182.             dataWide = bounds->right - bounds->left;
  3183.             if (rowBytes < 8)
  3184.                 isPacked = NO;
  3185.             else
  3186.                 isPacked = YES;
  3187.             //
  3188.             //    Start writing out data to the PS file.
  3189.             //
  3190.             [destFile   WriteInteger: bounds->left];
  3191.             [destFile   WriteInteger: bounds->top]; // because bottom in pict is top in ps..
  3192.             [destFile   WriteInteger: dataWide];
  3193.             [destFile   WriteInteger: dataHigh];
  3194.             [destFile  ForceNewLine];    // make sure the following data starts on a new line.
  3195.             //
  3196.             //    compute the relative scaling ratios of the bitmap (72dpi = 1)
  3197.             //    Convert first from fixedpoint data.
  3198.             //
  3199.             hScale = (theMap.hRes / 65535.0) / 72;
  3200.             vScale =  (theMap.vRes / 65535.0) / 72;
  3201.             [destFile   WriteInteger: (dataWide * hScale)];
  3202.             [destFile   WriteInteger: (dataHigh * vScale)];
  3203.             [destFile  ForceNewLine];    // make sure the following data starts on a new line.
  3204.             //
  3205.             //    Write whether the data is packed or not.  (for now, only pack because I
  3206.             //    could not figure out how to get filters to work inside a pattern proc.
  3207.             //
  3208.             [destFile WriteTextLine: "false"];
  3209.             //
  3210.             //    Now, write out the bitmap data itself converted.
  3211.             //
  3212.             [destFile WriteText: "<"];
  3213.             //
  3214.             //    A hack to wait until we can figure out how to unpack images in PS in
  3215.             //    indexed color spaces set packing so we never write out packed images
  3216.             //
  3217.             tempPacking = PackingSetting;    
  3218.             PackingSetting = NO;
  3219.  
  3220.             [self  ExtractImageDataUsingDataWidth: rowBytes
  3221.                 Scanlines: dataHigh
  3222.                 ScanlineLength:  rowBytes
  3223.                 ScanlineStart: 0
  3224.                 AndPixelDepth:  bitsDeep
  3225.                 IsCompressed: isPacked
  3226.                 UsesColor: YES];
  3227.             //
  3228.             //    Write a trailing > which an ASCIIHexEncoding  filter understands as EOF.
  3229.             //    If needed, also write an 80 which is eof for the RLE filter. 
  3230.             //
  3231.             if (PackingSetting == YES)
  3232.                 [destFile WriteTextLine: "80>"];
  3233.             else
  3234.                 [destFile WriteTextLine: ">"];
  3235.             [destFile   WritePositiveInteger: 1];
  3236.             PackingSetting = tempPacking;
  3237.             break;
  3238.         case 2 :
  3239.             //
  3240.             //    The 'pattern' is really halftone of the specified color.
  3241.             //    That is, you specify color XYZ, but device can't do this, so
  3242.             //    QuickDraw will build a raster using colors it can draw, that
  3243.             //    will approximate the color your want (specifed by the rgb value)
  3244.             //
  3245.             [self ConvertRGBColor];
  3246.             [destFile   WritePositiveInteger: 2];
  3247.             break;
  3248.         default :
  3249.             // Should set some kind big error here!
  3250.             break;
  3251.     }
  3252.     FreeCString(tempString);
  3253.     return self;
  3254. }
  3255.  
  3256.  
  3257.  
  3258.  
  3259.  
  3260. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3261. //    Method:        ConvertBitmapWithRegion:PackedData:
  3262. //    Parameters:    Boolean flag
  3263. //    Returns:     self
  3264. //    Stores:        none  explicitly
  3265. //    Description:
  3266. //        This reads a bitmap that may or may not have a clipping region, and may or
  3267. //        may not be packed.  It determines whether it is a B&W or color image, and then
  3268. //        extracts the appropriate data structures and writes them out.  
  3269. //    Bugs:
  3270. //        We don't examine the data nearly closely enough to assure that it is good.
  3271. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3272.  
  3273. -ConvertBitmapWithRegion: (Boolean) hasRegion PackedData: (Boolean) isPacked
  3274. {
  3275.     PICTRect*        bounds;
  3276.     PICTRect*        sourceRect;
  3277.     PICTRect*        destRect;
  3278.     modPixMap        theMap;
  3279.     PositiveInteger    dataHigh, dataWide;
  3280.     PositiveInteger    rowBytes;
  3281.     Integer            bytesOut;
  3282.     Integer            diff;
  3283.     Integer            bitmapOffset;
  3284.     Integer            rasterType;
  3285.     Integer            bitsDeep;
  3286.     Boolean            colorUse;
  3287.  
  3288.     rowBytes = [sourceFile   GetPositiveINTEGER];  // Retrieves a Mac INTEGER (16 bits)
  3289.     //
  3290.     //    Inside Mac  V says that if the high bit of rowBytes is set, then the picture is
  3291.     //    essentially one with multiple bits per pixel.  SO.  Check the high bit (mask the
  3292.     //    rowBytes and check if zero or not), and also check for Pict version number.
  3293.     //    if the version is 1, then ignore that the high bit is set.
  3294.     //    In either case, process all the leading information up to the bitmap data.
  3295.     //
  3296.     if   (((rowBytes & 0x8000) == 0) || ([sourceFile   GetVersion] == 1))
  3297.     {
  3298.         //
  3299.         //    Write the two 'dummy' pieces of data so that the output from the two pict
  3300.         //    types of bitmaps have the same parameters, allowing one more flexibility in
  3301.         //    writing PS code.
  3302.         //
  3303.         [destFile   WritePositiveInteger:  1];    // num colors  -1
  3304.         [destFile   WriteTextLine:  "< 000000 FFFFFF >"];
  3305.         bounds = [sourceFile   GetRect];
  3306.         rasterType = 1;
  3307.         bitsDeep = 1;
  3308.     }
  3309.     else
  3310.     {
  3311.         //
  3312.         //    Clear the high bit of rowBytes, read in the pixmap data, and convert
  3313.         //    the color table that follows it.
  3314.         //
  3315.         rowBytes = 0x7FFF & rowBytes;
  3316.         [self   GetPixMapFrom: sourceFile  Into: &theMap];
  3317.         [self  ConvertColorTable];
  3318.         //
  3319.         //    move the rectangle bounding data into the bounds rect..
  3320.         //
  3321.         bounds    = (PICTRect*)NewByteString(sizeof(PICTRect));
  3322.         bounds->left = theMap.bounds.left;
  3323.         bounds->top = theMap.bounds.top;
  3324.         bounds->bottom = theMap.bounds.bottom;
  3325.         bounds->right = theMap.bounds.right;
  3326.         rasterType = 2;
  3327.         bitsDeep = theMap.pixelSize;
  3328.     }
  3329.     [destFile   WriteInteger: bitsDeep];
  3330.  
  3331.     //
  3332.     //    Read the source and dest rectangles in from the bitmap
  3333.     //
  3334.     sourceRect = [sourceFile   GetRect];
  3335.     destRect = [sourceFile   GetRect];
  3336.     //
  3337.     //    Start writing out data to the PS file.
  3338.     //        Convert and write out the transver mode
  3339.     //        Write the left and bottom coordinates of the destination rectangle
  3340.     //            (note that bottom in PS coords is top in PICT)
  3341.     //        Write the height and width of the destination rectangle
  3342.     //        Write the height and width of the source rectangle
  3343.     //        IF there is a region, convert it. In either case, write a flag indicating whether
  3344.     //            there is a region written out.
  3345.     //
  3346.     [self ConvertMode];
  3347.     [destFile   WriteInteger: destRect->left];
  3348.     [destFile   WriteInteger: destRect->top];    // because bottom right in pict is top in ps..
  3349.     [destFile   WriteInteger: destRect->right - destRect->left];
  3350.     [destFile   WriteInteger: destRect->bottom - destRect->top];
  3351.     [destFile   WriteInteger: sourceRect->right - sourceRect->left];
  3352.     [destFile   WriteInteger: sourceRect->bottom - sourceRect->top];
  3353.     [destFile  ForceNewLine];    // make sure the following data starts on a new line.
  3354.     //
  3355.     //    Write whether the data is packed or not.
  3356.     //
  3357.     if (PackingSetting == YES)
  3358.         [destFile WriteTextLine: "true"];
  3359.     else
  3360.         [destFile WriteTextLine: "false"];
  3361.     if (hasRegion == YES)
  3362.     {
  3363.         [self ConvertRegion];
  3364.         [destFile WriteTextLine: "true"];
  3365.     }
  3366.     else
  3367.         [destFile WriteTextLine: "false"];
  3368.     //
  3369.     //    Compute data needed for consumption of the bitmap.  Specifically:
  3370.     //    Determine how many pixels high and wide the image rectangle is.
  3371.     //    This figure very likely differs from the rowBytes width, so figure out exactly
  3372.     //    how many BYTES are in the width of the bitmap to go out.
  3373.     //    Then, figure out what the offset of the start of this bitmap in the raw data is,
  3374.     //    since strangely a bitmapped image is not always left justified in a pict bitmap...
  3375.     //
  3376.     dataHigh = bounds->bottom - bounds->top;
  3377.     dataWide = sourceRect->right - sourceRect->left;
  3378.     diff = ( (rowBytes*8) - (dataWide *bitsDeep) ) / 8;
  3379.     bytesOut = rowBytes -diff;    // remove any 'fluf' bytes.
  3380.     bitmapOffset = sourceRect->left - bounds->left; // there may be a strange offset
  3381.     //
  3382.     //    Now, write out the command to PS, and then have the bitmap data itself converted.
  3383.     //
  3384.     if (rasterType == 1)
  3385.     {
  3386.         colorUse = NO;
  3387.         [destFile WriteTextLine: "bitmap"];
  3388.     }
  3389.     else
  3390.     {
  3391.         colorUse = YES;
  3392.         [destFile WriteTextLine: "colorbitmap"];
  3393.     }
  3394.  
  3395.     [self  ExtractImageDataUsingDataWidth: rowBytes
  3396.         Scanlines: dataHigh
  3397.         ScanlineLength:  bytesOut
  3398.         ScanlineStart: bitmapOffset
  3399.         AndPixelDepth:  bitsDeep
  3400.         IsCompressed: isPacked
  3401.         UsesColor: colorUse];
  3402.     //
  3403.     //    Write a trailing > which an ASCIIHexEncoding  filter understands as EOF.
  3404.     //    If needed, also write an 80 which is eof for the RLE filter. 
  3405.     //
  3406.     if (PackingSetting == YES)
  3407.         [destFile WriteTextLine: "80>"];
  3408.     else
  3409.         [destFile WriteTextLine: ">"];
  3410.     FreeByteString((ByteString)bounds);
  3411.     FreeByteString((ByteString)sourceRect);
  3412.     FreeByteString((ByteString)destRect);
  3413.     return self;
  3414. }
  3415.  
  3416.  
  3417.  
  3418.  
  3419. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3420. //    Method:    ExtractPackedImageDataUsingDataWidth:Scanlines:ScanlineLength:
  3421. //            ScanlineStart:AndPixelDepth:IsCompressed:UsesColor:
  3422. //    Parameters:
  3423. //        A count of the number of bytes per row of raw bit data
  3424. //        A count of the number of scanlines in the file
  3425. //        The number of bytes per scanline
  3426. //        The number of bits offset into the raw scanline data that the bitmap starts
  3427. //        The number of bits that represent a pixel
  3428. //        A flag indicating whether the data is compressed
  3429. //        A flag indicating whether color was used.
  3430. //    Returns:     self
  3431. //    Stores:        none
  3432. //    Description:
  3433. //        This consumes the packed raw data from the sourcefile, interpreting it as bitmap
  3434. //        data using the parameters given.  This raw data can be viewed as a rectangle of
  3435. //        DataWidth bytes wide and Scanlines rows tall.  The interesting part of the bitmap
  3436. //        is in the sub-rectangle that is scanlines rows tall and scanlinelength bytes wide.
  3437. //        This subrectangle may be identical to the first, or smaller (in which case, it may be
  3438. //        inset on the left by scanlinesstart bits.)  If the data is packed, then we unpack it
  3439. //        one scanline at a time, and write it out, inverting it if it is B&W, and packing it if
  3440. //        the master object has told us to.
  3441. //        The failing of this routine, perhaps, is that it attempts to do everything at once
  3442. //        (it used to be at least two that did a lot of similar, and a bit of different things), so
  3443. //        it gets a bit complex near the end...
  3444. //    Bugs:
  3445. //        It should be possible to bypass the unpacking and repacking for color images.
  3446. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3447.  
  3448. - ExtractImageDataUsingDataWidth: (PositiveInteger) rawWidth
  3449.     Scanlines: (Integer) numLines
  3450.     ScanlineLength: (Integer) bytesPerScanline
  3451.     ScanlineStart: (Integer) bitOffset
  3452.     AndPixelDepth: (Integer) numBits
  3453.     IsCompressed: (Boolean)  sourcePacked
  3454.     UsesColor: (Boolean) ColorUsed
  3455. {
  3456.     PositiveInteger    index;
  3457.     Integer            byteCount;
  3458.     Integer            lastSize        = rawWidth;
  3459.     ByteString        preLine        = NewByteString(rawWidth);
  3460.     ByteString        destLine        = NewByteString (rawWidth);
  3461.     ByteString        sourceLine    = NewByteString (rawWidth);
  3462.     ByteString        packedLine    = NewByteString(rawWidth*1.5); // crude worst pack case
  3463.     Integer            numOut;
  3464.     ByteString        temp;
  3465.     Real                fileSize        = ( [sourceFile   FileSize] * 1.0);
  3466.     // divide  the above by 100 now so later division will yeild number between 0 and 100
  3467.  
  3468.     for (index = 0; index < numLines; index ++)
  3469.     {
  3470.         //
  3471.         //    Let the user know that we're actually doing something.
  3472.         //
  3473.         if ((index % 35) == 0)
  3474.         {
  3475.             if ( [myManager   respondsTo:@selector(SetPercentageDone:)] ) 
  3476.                 [myManager   SetPercentageDone: ([sourceFile   GetCurrentPosition] * 100.0) / fileSize];
  3477.         }
  3478.         //
  3479.         //    Read in the source bitmap line, unpacking it if necessary
  3480.         //
  3481.         if (sourcePacked == NO)
  3482.             [sourceFile   Read: rawWidth BytesInto: sourceLine];
  3483.         else
  3484.         {
  3485.             //
  3486.             //    Get the length of the packed record.  (if rawWidth > 250, we use a 16 bit
  3487.             //    integer to determine the size.  This is documented on p. 105 of IM V.
  3488.             //    I do NOT know if this applies to PICT 1 data, but I'm assuming so.)
  3489.             //
  3490.             if (rawWidth > 250)
  3491.                 byteCount = [sourceFile   GetINTEGER];
  3492.             else
  3493.                 byteCount = [sourceFile  GetByte];
  3494.             //
  3495.             //    If the lastpreLine buffer won't hold the whole packed data, then free it and
  3496.             //    allocate a new one (this prevents needing to reallocate *every* time,
  3497.             //    without our needing to necessarily allocate a buffer of maximum size
  3498.             //    (whatever that would be)
  3499.             //
  3500.             if (byteCount > lastSize)
  3501.             {
  3502.                 FreeByteString(preLine);
  3503.                 preLine = NewByteString (byteCount);
  3504.                 lastSize = byteCount;
  3505.             }
  3506.             //
  3507.             //    Read in the packed data and unpack it.
  3508.             //
  3509.             [sourceFile   Read: byteCount BytesInto: preLine];
  3510.             [self Unpack: rawWidth BytesFrom: preLine Into: sourceLine];
  3511.         }
  3512.         //////
  3513.         //    At this point, we should have our raw non-packed scanline data.
  3514.         //////
  3515.         //
  3516.         //    If the bitdata is offset, then shift it left appropiately, and reverse pointers from
  3517.         //    dest and source lines (this allows the following routine to use the same variables
  3518.         //    regardless of whether we did this or not.
  3519.         //
  3520.         if (bitOffset != 0)
  3521.         {
  3522.             [self   Copy: (bytesPerScanline*8) BitsAtOffset: bitOffset
  3523.                 From: sourceLine Into: destLine];
  3524.             temp = destLine;
  3525.             destLine = sourceLine;
  3526.             sourceLine = temp;
  3527.         }
  3528.         //
  3529.         //    Invert the data if it is B&W, and then pack the data if the manager has asked us
  3530.         //    to (set temp to point to final buffer, and numOut to be it's length)
  3531.         //
  3532.         if ( (numBits == 1) && (ColorUsed == NO) )
  3533.             [self   Invert: bytesPerScanline In: sourceLine];
  3534.         if (PackingSetting == YES)
  3535.         {
  3536.             numOut = [self   Pack: bytesPerScanline BytesFrom: sourceLine
  3537.                         Into: packedLine];
  3538.             temp = packedLine;
  3539.         }
  3540.         else
  3541.         {
  3542.             numOut = bytesPerScanline;
  3543.             temp = sourceLine;
  3544.         }
  3545.         //
  3546.         //    write out the scanline of bits as PS hex data.
  3547.         //
  3548.         [destFile   Write: numOut BytesOfHexDataFrom: temp];
  3549.     }
  3550.     FreeByteString (sourceLine);
  3551.     FreeByteString (destLine);
  3552.     FreeByteString (packedLine);
  3553.     FreeByteString (preLine);
  3554.     return self;
  3555. }
  3556.  
  3557.  
  3558. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3559. //    Method:        ConvertColorTable
  3560. //    Parameters:    none
  3561. //    Returns:     self
  3562. //    Stores:        none
  3563. //    Description:
  3564. //        This reads a PICT2 color table from the source file  (it assumes that the
  3565. //        source file is positioned at the start of one), and converts it into a PS Level 2
  3566. //        indexed colorspace definition.
  3567. //        Note: PICT Color tables use 16 bits per color component, in terms of storage.
  3568. //        Still, I've not seen any using more than the 8 bits (to get a total of 24bit color).
  3569. //        I'm sure it's possible there are 48 bit color values somewhere out there, but I
  3570. //        also can't find a definition of how to determine this.  It probably has to do with
  3571. //        some of the other values in the pixmap which IM V defines as being set to 0
  3572. //        Note: I did run across a pixel paint file which use only 8 bits, and then wrote a
  3573. //        number (e.g. AA01 A301 B201  for a color value of AA A3 B2, and incremented to
  3574. //        02 for next, etc), so it seems that one must assume 8 at least for now...
  3575. //    Bugs:
  3576. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3577. - ConvertColorTable
  3578. {
  3579.     PositiveInteger    numEntries;
  3580.     PositiveInteger    index;
  3581.     CString            buffer        = NewCString(40);
  3582.     Byte            Red,
  3583.                     Green,
  3584.                     Blue;
  3585.     //
  3586.     //    Skip the color table's seed and flag values
  3587.     //
  3588.     [sourceFile   AdvanceBytes: 6];
  3589.     //
  3590.     //    Get the number of color entries in the table (0 origin)
  3591.     //
  3592.     numEntries  = [sourceFile   GetPositiveINTEGER];
  3593.     //
  3594.     //    Start off the PS color table with the start of the indexed color space array
  3595.     //
  3596.     [destFile   WritePositiveInteger:  numEntries];
  3597.     [destFile   WriteText:  "<"];
  3598.     //
  3599.     //    Write out the rgb color data.  Put a limited number of color values on an output line
  3600.     //
  3601.     for (index = 0; index <= numEntries; index++)
  3602.     {
  3603.         [sourceFile   AdvanceBytes: 2];    // skip over the index  (assure they are sequential?)
  3604.         //
  3605.         //    Read the color components in.  Note that PICT uses 16 bits per color component,
  3606.         //    however, we can only use 8 here due to the indexed color space strategy I'm using
  3607.         //    in PS.  This actually seems to be not loose anything as far as I've seen so far.
  3608.         //
  3609.         Red = [sourceFile   GetByte];
  3610.         [sourceFile  AdvanceBytes: 1];
  3611.         Green = [sourceFile   GetByte];
  3612.         [sourceFile  AdvanceBytes: 1];
  3613.         Blue = [sourceFile   GetByte];
  3614.         [sourceFile  AdvanceBytes: 1];
  3615.         //
  3616.         //    If we've not written a nultiple of 9 colors, just write out the color in FF4502 form
  3617.         //    (FF red, 45 green, 02 blue).  If we have written 9, then put a newline afterwards
  3618.         //
  3619.         if (((index+1) % 9) != 0)
  3620.         [destFile   WriteTextUsing: buffer WithFormat: "%.2x%.2x%.2x ", Red, Green, Blue];
  3621.         else
  3622.         [destFile   WriteTextUsing: buffer WithFormat: "%.2x%.2x%.2x\n", Red, Green, Blue];
  3623.     }
  3624.     //
  3625.     //    Close the array and quit
  3626.     //
  3627.     [destFile   WriteTextLine: ">"];
  3628.     FreeCString(buffer);
  3629.     return self;
  3630. }
  3631.  
  3632.  
  3633. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3634. //    Method:        ConvertDirectBitmapWithRegion:
  3635. //    Parameters:    Boolean flag
  3636. //    Returns:     self
  3637. //    Stores:        none  explicitly
  3638. //    Description:
  3639. //        This routines reads in and processes one of the 'direct' bitmap structres in a
  3640. //        pict file (opcodes 9a and 9b).  These are bitmaps that have no clut's, but are direct
  3641. //        representations of color values in the pixels.
  3642. //    History:
  3643. //        93.08.21    djb    Created.
  3644. //    Bugs:
  3645. //        16bit images are completely ignored.  I'm not convinced I've got all
  3646. //        32bit cases dealt with.  Too little resources to test with.
  3647. //        Yep, properly rowbytes should be part of the pixmap.  However, it had to be
  3648. //        examind in advance in the other bitmap conversion routine, since the pixmap
  3649. //        isn't there for older bitmaps, and I didn't figure it was worth a second pixmap
  3650. //        reading routine given that.  (similar for the baseaddress field)
  3651. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3652.  
  3653. -ConvertDirectBitmapWithRegion: (Boolean) hasRegion
  3654. {
  3655.     PICTRect*        sourceRect    = NULL;
  3656.     PICTRect*        destRect        = NULL;
  3657.     modPixMap        theMap;
  3658.     PositiveInteger    dataHigh, dataWide;
  3659.     PositiveInteger    rowBytes;
  3660.     Integer            bytesOut;
  3661.     Integer            diff;
  3662.     Integer            bitmapOffset;
  3663.     Integer            bitsDeep;
  3664.     Integer            index;
  3665.     Integer            count;
  3666.     Integer            decider;
  3667.     //
  3668.     //    Skip the baseaddress field.  It should just contain 0x000000FF, anyway.
  3669.     //
  3670.     [sourceFile   GetLONGINT];
  3671.     //
  3672.     //    Read in rowbytes, but do nothing with it for now, and then read in the pixmap.
  3673.     //
  3674.     rowBytes = [sourceFile   GetPositiveINTEGER];
  3675.     rowBytes = 0x7FFF & rowBytes;
  3676.     [self   GetPixMapFrom: sourceFile  Into: &theMap];
  3677.     //
  3678.     //    Insert a real hack.  Someday we may indeed want to process 16 bit
  3679.     //    images.  But, for now the ambiguity in Inside mac, coupled with a lack
  3680.     //    of samples here, coupled with the fact that I have no personal interest in
  3681.     //    getting it done just now (someday, but not just now), really does motivate
  3682.     //    me to put this hack in.
  3683.     //
  3684.     if (theMap.pixelSize == 16)
  3685.     {
  3686.         [self   StoreErrorCode: ERR_NOSIXTEEN
  3687.             AndText: "Convert PICT found a 16bit image.  Alas, this version is not able to process those.  Your image can not be converted here."];
  3688.         goto HACKGOTO;
  3689.     }
  3690.     
  3691.     //
  3692.     //    Read the source and dest rectangles in from the bitmap
  3693.     //
  3694.     sourceRect = [sourceFile   GetRect];
  3695.     destRect = [sourceFile   GetRect];
  3696.     //
  3697.     //    Start writing out data to the PS file.
  3698.     //        Convert and write out the transfer mode
  3699.     //        Write the left and bottom coordinates of the destination rectangle
  3700.     //            (note that bottom in PS coords is top in PICT)
  3701.     //        Write the height and width of the destination rectangle
  3702.     //        Write the height and width of the source rectangle
  3703.     //        IF there is a region, convert it. In either case, write a flag indicating whether
  3704.     //            there is a region written out.
  3705.     //
  3706.     [self ConvertMode];
  3707.     [destFile   WriteInteger: destRect->left];
  3708.     [destFile   WriteInteger: destRect->top];    // because bottom right in pict is top in ps..
  3709.     [destFile   WriteInteger: destRect->right - destRect->left];
  3710.     [destFile   WriteInteger: destRect->bottom - destRect->top];
  3711.     [destFile   WriteInteger: sourceRect->right - sourceRect->left];
  3712.     [destFile   WriteInteger: sourceRect->bottom - sourceRect->top];
  3713.     [destFile  ForceNewLine];    // make sure the following data starts on a new line.
  3714.     if (PackingSetting == YES)
  3715.         [destFile WriteTextLine: "true"];
  3716.     else
  3717.         [destFile WriteTextLine: "false"];
  3718.     if (hasRegion == YES)
  3719.     {
  3720.         [self ConvertRegion];
  3721.         [destFile WriteTextLine: "true"];
  3722.     }
  3723.     else
  3724.         [destFile WriteTextLine: "false"];
  3725.     //
  3726.     //    Compute data needed for consumption of the bitmap.  Specifically:
  3727.     //    Determine how many pixels high and wide the image rectangle is.
  3728.     //    This figure very likely differs from the rowBytes width, so figure out exactly
  3729.     //    how many BYTES are in the width of the bitmap to go out.
  3730.     //    Then, figure out what the offset of the start of this bitmap in the raw data is,
  3731.     //    since strangely a bitmapped image is not always left justified in a pict bitmap...
  3732.     //
  3733.     dataHigh = theMap.bounds.bottom - theMap.bounds.top;
  3734.     dataWide = sourceRect->right - sourceRect->left;
  3735.     diff = ( (rowBytes*8) - (dataWide *bitsDeep) ) / 8;
  3736.     bytesOut = rowBytes -diff;    // remove any 'fluf' bytes.
  3737.     bitmapOffset = sourceRect->left - theMap.bounds.left; // there may be a strange offset
  3738.     //
  3739.     //    Now, write out the command to PS, and then have the bitmap data itself converted.
  3740.     //
  3741.     [destFile WriteTextLine: "24bitBitmap"];
  3742.     //
  3743.     //    Set up a value, and then switch on it to determine what packing type we are using.
  3744.     //
  3745.     decider = theMap.packType;
  3746.     if (rowBytes < 8)
  3747.         decider = 1;
  3748.     switch (decider)
  3749.     {
  3750.         case 1:
  3751.             [self   ConvertPackType1WithHeight: dataHigh
  3752.                 AndWidth: rowBytes
  3753.                 AndOffiset: bitmapOffset];
  3754.             break;
  3755.         case 2:
  3756.             [self   ConvertPackType2WithHeight: dataHigh
  3757.                 AndWidth: rowBytes
  3758.                 AndOffiset: bitmapOffset];
  3759.             break;
  3760.         case 3:
  3761.             // 16 bit image.  Skipped by thing above
  3762.             break;
  3763.         case 4:
  3764.             [self   ConvertPackType4WithHeight: dataHigh
  3765.                 AndWidth: rowBytes
  3766.                 AndOffiset: bitmapOffset];
  3767.             break;
  3768.         default:
  3769.             if (theMap.packType < 0)
  3770.             {
  3771.                 [self   StoreErrorCode: ERR_BADPACK
  3772.                     AndText: "Encountered an unknown packType when converting an image.  Your PICT file may be bad."];
  3773.             }
  3774.             else
  3775.             {
  3776.                 for (index = 1; index <= dataHigh; index++)
  3777.                 {
  3778.                     if (rowBytes > 250)
  3779.                         count = [sourceFile  GetINTEGER];
  3780.                     else
  3781.                         count = [sourceFile   GetByte];
  3782.                     [sourceFile   AdvanceBytes: count];
  3783.                 }
  3784.                 [self   StoreErrorCode: ERR_UNKNOWNPACK
  3785.                     AndText: "Encountered an unknown packType  when converting an image.  Unable to convert it."];
  3786.             }
  3787.             break;
  3788.     }
  3789.  
  3790.     HACKGOTO:
  3791.  
  3792.     FreeByteString((ByteString)sourceRect);
  3793.     FreeByteString((ByteString)destRect);
  3794.     return self;
  3795. }
  3796.  
  3797.  
  3798. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3799. //    Method:        ConvertPackType1WithHeight:AndWidth:AndOffset:
  3800. //    Parameters:
  3801. //                height of bitmap (in pixels)
  3802. //                width of bitmap (pixels)
  3803. //                count of bitmap offset.
  3804. //    Returns:     self
  3805. //    Stores:        none  explicitly
  3806. //    Description:
  3807. //        This extracts a 'direct' bitmap that was stored with packing type 1.
  3808. //        Apparently, this is used only with 16 and 32bit color images.
  3809. //        In this packing scheme, the pixel values are not altered at all.  So, we do
  3810. //        nothing with them but write them out in hex, and potentially rle
  3811. //        encode them..
  3812. //    History:
  3813. //        93.08.21    djb    Created.
  3814. //    Bugs:
  3815. //        We ignore the offset value.  It's conceivable, but I don't know if it's probable,
  3816. //        that the bitmap would not be left aligned.  If not, we would need the offset to
  3817. //        fix the problem.  This probably only occurrs with bitmaps whose pixel size is
  3818. //        less than a byte.
  3819. //        This will fail to work for 16 bit graphics, actually.  However, since our
  3820. //        caller discards 16 bit values for now, we can also ignore them.
  3821. //        Warning!  Rowbytes may need to be multiplied by .75! if this is 32 bit
  3822. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3823. - ConvertPackType1WithHeight: (Integer) dataHigh
  3824.                 AndWidth: (Integer) rowBytes
  3825.                 AndOffiset: (Integer) bitmapOffset
  3826. {
  3827.     Integer    index;
  3828.     Integer    bytesPerRow;
  3829.     ByteString    scanline;
  3830.     ByteString    packedline;
  3831.     Integer    packlength;
  3832.     
  3833.     bytesPerRow = rowBytes;
  3834.     scanline = NewByteString(bytesPerRow);
  3835.     packedline = NewByteString(bytesPerRow*2);
  3836.     
  3837.     for (index = 1; index <= dataHigh; index++)
  3838.     {
  3839.         [sourceFile   Read: bytesPerRow BytesInto: scanline];
  3840.         if (PackingSetting == YES)
  3841.         {
  3842.             packlength = [self  Pack: bytesPerRow BytesFrom:  scanline Into:  packedline];
  3843.             [destFile   Write: packlength BytesOfHexDataFrom: packedline    ];
  3844.         }
  3845.         else
  3846.             [destFile   Write: bytesPerRow BytesOfHexDataFrom: scanline];
  3847.     }
  3848.     
  3849.     FreeByteString(packedline);
  3850.     FreeByteString(scanline);
  3851.     return self;
  3852. }
  3853.  
  3854.  
  3855. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3856. //    Method:        ConvertPackType2WithHeight:AndWidth:AndOffset:
  3857. //    Parameters:
  3858. //                height of bitmap (in pixels)
  3859. //                width of bitmap (pixels)
  3860. //                count of bitmap offset.
  3861. //    Returns:     self
  3862. //    Stores:        none  explicitly
  3863. //    Description:
  3864. //        This extracts a 'direct' bitmap that was stored with packing type 2.
  3865. //        This packing type is used only for 32bit images where each pixel is
  3866. //        represented by 3 componets of 8 bytes each (RGB) and one spare 8 byte component.
  3867. //        In this packing scheme, that spare component is removed.  We simply read the
  3868. //        bitmap data in, and turn around and write it back out.
  3869. //    History:
  3870. //        93.08.21    djb    Created.
  3871. //    Bugs:
  3872. //        We ignore the offset value.  It's conceivable, but I don't know if it's probable,
  3873. //        that the bitmap would not be left aligned.  If not, we would need the offset to
  3874. //        fix the problem.  This probably only occurrs with bitmaps whose pixel size is
  3875. //        less than a byte.
  3876. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3877. - ConvertPackType2WithHeight: (Integer) dataHigh
  3878.                 AndWidth: (Integer) rowBytes
  3879.                 AndOffiset: (Integer) bitmapOffset
  3880. {
  3881.     Integer    bytesPerRow;
  3882.     ByteString    scanline;
  3883.     ByteString    packedline;
  3884.     Integer    packlength;
  3885.     
  3886.     bytesPerRow = rowBytes * .75;    // so sayeth the color quickdraw section of inside mac VI
  3887.     scanline = NewByteString(bytesPerRow);
  3888.     packedline = NewByteString(bytesPerRow*2);
  3889.     
  3890.     [sourceFile   Read: bytesPerRow BytesInto: scanline];
  3891.     if (PackingSetting == YES)
  3892.     {
  3893.         packlength = [self  Pack: bytesPerRow BytesFrom:  scanline Into:  packedline];
  3894.         [destFile   Write: packlength BytesOfHexDataFrom: packedline];
  3895.     }
  3896.     else
  3897.         [destFile   Write: bytesPerRow BytesOfHexDataFrom: scanline];
  3898.  
  3899.     FreeByteString(packedline);
  3900.     return self;
  3901. }
  3902.  
  3903.  
  3904. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3905. //    Method:        ConvertPackType4WithHeight:AndWidth:AndOffset:
  3906. //    Parameters:
  3907. //                height of bitmap (in pixels)
  3908. //                width of bitmap (pixels)
  3909. //                count of bitmap offset.
  3910. //    Returns:     self
  3911. //    Stores:        none  explicitly
  3912. //    Description:
  3913. //        This extracts a 'direct' bitmap that was stored with packing type 4.
  3914. //        This packing type is used only for 32bit images where there are 3 components used
  3915. //        per pixel.  The scheme is simple.  Each scanline is compressed using packbits.
  3916. //    History:
  3917. //        93.08.21    djb    Created.
  3918. //    Bugs:
  3919. //        We ignore the offset value.  It's conceivable, but I don't know if it's probable,
  3920. //        that the bitmap would not be left aligned.  If not, we would need the offset to
  3921. //        fix the problem.  This probably only occurrs with bitmaps whose pixel size is
  3922. //        less than a byte.
  3923. //        If the image happens to have 4 components per pixel, we are going to die.
  3924. //        The doc says nothing about manipulating rowbytes, explicitly.  Yet, the example
  3925. //        of this type that i have had it multiplied by .75 (to take into account the lack of
  3926. //        a fourth component.  It may be simplistic to assume I should always be doing this?
  3927. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3928. - ConvertPackType4WithHeight: (Integer) dataHigh
  3929.                 AndWidth: (Integer) rowBytes
  3930.                 AndOffiset: (Integer) bitmapOffset
  3931. {
  3932.     Integer            index;
  3933.     Integer            bytesPerRow;
  3934.     ByteString        weirdline;
  3935.     ByteString        inputline;
  3936.     ByteString        sortedline;
  3937.     PositiveInteger    count;
  3938.     PositiveInteger    numPixels;
  3939.     PositiveInteger    pixel;
  3940.     ByteString        redAddr;
  3941.     ByteString        greenAddr;
  3942.     ByteString        blueAddr;
  3943.  
  3944.     bytesPerRow = .75 * rowBytes;    // See above.
  3945.     numPixels = .25 * rowBytes;    // get length of one set of components
  3946.     inputline = NewByteString(bytesPerRow*2);
  3947.     weirdline = NewByteString(bytesPerRow);
  3948.     sortedline = NewByteString(bytesPerRow);
  3949.  
  3950.     for (index = 1; index <= dataHigh; index++)
  3951.     {
  3952.         if (rowBytes > 250)
  3953.             count = [sourceFile  GetPositiveINTEGER];
  3954.         else
  3955.             count = [sourceFile   GetByte];
  3956.  
  3957.         [sourceFile   Read: count BytesInto: inputline];
  3958.         //
  3959.         //    Now, we must unpack the data, because as it stands, it is made up of
  3960.         //    the RGB values, with all the R values first, then all the G, etc...
  3961.         //    So, we unpack it, and then reorganize the bytes that make up the components
  3962.         //    of each pixel, sorting them into an RGB order for the postscript routine.
  3963.         //
  3964.         [self Unpack: bytesPerRow BytesFrom: inputline Into: weirdline];
  3965.         redAddr = weirdline;
  3966.         greenAddr = &weirdline[numPixels];
  3967.         blueAddr = &weirdline[numPixels * 2];
  3968.  
  3969.         for (pixel = 0; pixel < numPixels; pixel++)
  3970.         {
  3971.             sortedline[pixel*3] = redAddr[pixel];
  3972.             sortedline[(pixel*3)+1] = greenAddr[pixel];
  3973.             sortedline[(pixel*3)+2] = blueAddr[pixel];
  3974.         }
  3975.         //
  3976.         //    Whew!  Now that that is done, we turn around and pack the line (if needed)
  3977.         //    and write it out.
  3978.         //
  3979.         if (PackingSetting == YES)
  3980.         {
  3981.             //
  3982.             //    Reuse inputline and count.  What the heck. 
  3983.             //
  3984.             count = [self Pack: bytesPerRow BytesFrom: sortedline Into: inputline];
  3985.             [destFile   Write: count BytesOfHexDataFrom: inputline];
  3986.         }
  3987.         else
  3988.         {
  3989.             [destFile   Write: bytesPerRow BytesOfHexDataFrom: sortedline];
  3990.         }
  3991.     }
  3992.  
  3993.     FreeByteString(sortedline);
  3994.     FreeByteString(weirdline);
  3995.     FreeByteString(inputline);
  3996.  
  3997.     return self;
  3998. }
  3999.  
  4000.  
  4001.         
  4002. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4003. //    Method:    Unpack:BytesFrom:Into:
  4004. //    Parameters:
  4005. //        A count of the number of bytes to unpack
  4006. //        A source string
  4007. //        A destination string.
  4008. //    Returns:     self
  4009. //    Stores:        none
  4010. //    Description:
  4011. //        This repeatedly unpacks runs from the source line, and stores them into
  4012. //        destline.  It stops only when numBytes have been written to destLine.
  4013. //        NOTE: This, then, watches for no stop marker in the sourceLine.  If data is
  4014. //        malformed, or numBytes is bad, this may careen into space that doesn't belong to it.
  4015. //        It is also assumed that destLine is large enough for whatever gets unpacked.
  4016. //        This algorithm is, I believe, documented in, Adobe's PS level 2 reference manual
  4017. //        reference manual as their simple RLE filter and in an Apple tech note on PackBits
  4018. //    Bugs:
  4019. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4020. - Unpack: (PositiveInteger) numBytes BytesFrom:  (ByteString) sourceLine
  4021.     Into:  (ByteString) destLine
  4022. {
  4023.     Byte        flag;
  4024.     Byte        dataByte;
  4025.     Integer    index;
  4026.     Integer    sourceIndex = 0;
  4027.     Integer    destIndex = 0;
  4028.  
  4029.     do
  4030.     {
  4031.         flag = sourceLine[sourceIndex];
  4032.         sourceIndex++;
  4033.         if (flag < 128)
  4034.         {
  4035.             //
  4036.             //    Copy one more than the number of bytes specified by flag litterally.
  4037.             //
  4038.             flag++;
  4039.             for (index = 0; index < flag; index++)
  4040.             {
  4041.                 destLine[destIndex] =  sourceLine[sourceIndex];
  4042.                 sourceIndex++;
  4043.                 destIndex++;
  4044.             }
  4045.         }
  4046.         else
  4047.         {
  4048.             //
  4049.             //    Copy the next byte 257-flag times
  4050.             //
  4051.             dataByte =sourceLine[sourceIndex];
  4052.             sourceIndex++;
  4053.             for (index = 0; index < (257 -flag); index ++)
  4054.             {
  4055.                 destLine[destIndex] = dataByte;
  4056.                 destIndex++;
  4057.             }
  4058.         }
  4059.     }
  4060.     while (destIndex < numBytes);
  4061.     return self;
  4062. }
  4063.  
  4064.  
  4065. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4066. //    Method:    Pack:BytesFrom:Into:
  4067. //    Parameters:
  4068. //        A count of the number of bytes to pack
  4069. //        A source string
  4070. //        A destination string.
  4071. //    Returns:     the size of the packed data
  4072. //    Stores:        none
  4073. //    Description:
  4074. //        This will pack the source line into the dest line, stopping only after it has written
  4075. //        lineLength bytes from source.  This assumes that the length parameter is good,
  4076. //        and that the source buffer has that many bytes, and that dest buffer has enough
  4077. //        space for the packing (I really should calculate a worst case scenario some time)
  4078. //        This data format is, I believe, documented in, Adobe's PS level 2 reference manual
  4079. //        reference manual as their simple RLE filter and in an Apple tech note on PackBits
  4080. //    Bugs:
  4081. //        This routine is not commented enough.
  4082. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4083. -(PositiveInteger) Pack: (PositiveInteger) lineLength BytesFrom:  (ByteString) source
  4084.     Into:  (ByteString) dest
  4085. {
  4086.     Boolean    runs = NO;
  4087.     Integer    numTraversedBytes;
  4088.     Integer    startByte = 0;
  4089.     Integer    index = 0;
  4090.     Integer    destIndex = 0;
  4091.     Integer    ctr;
  4092.     
  4093.         index = 0;
  4094.         do
  4095.         {
  4096.             startByte = index;
  4097.             //
  4098.             //    first Byte is always assumed to be OK.  Safe assumption.  Either
  4099.             //    we are starting (Byte 0 should always be good), or we just dumped
  4100.             //    some data, at which index points to the first Byte that did not match
  4101.             //    that pattern, and so is good to use for starting with the next
  4102.             //
  4103.             index++;
  4104.             //
  4105.             // Try to accumulate a run
  4106.             //
  4107.             while ((source[index-1] == source[index]) &&
  4108.                     ((index-startByte) < 128) &&
  4109.                     (index < lineLength))
  4110.                 { index++; }
  4111.             if ((index-startByte) > 2)
  4112.                 runs = YES;
  4113.             else
  4114.             {
  4115.                 //
  4116.                 //    not enough to justify a run, so carry on. as a litteral sequence of Bytes
  4117.                 //
  4118.                 while ((source[index-1] != source[index]) &&
  4119.                         ((index-startByte) < 128) &&
  4120.                         (index < lineLength))
  4121.                     { index++; }
  4122.                 if (index < lineLength) // We ran into a match, not the end
  4123.                     { index--; }    // Thus, back up over 1 of the 2 Bytes.
  4124.                 runs = NO;
  4125.             }
  4126.             numTraversedBytes = index-startByte;
  4127.             if (runs == YES) 
  4128.             {
  4129.                 dest[destIndex] = 257-numTraversedBytes;
  4130.                 destIndex++;
  4131.                 dest[destIndex] = source[startByte];
  4132.                 destIndex++;
  4133.             }
  4134.             else
  4135.             {
  4136.                 dest[destIndex] = numTraversedBytes - 1;
  4137.                 destIndex++;
  4138.                 for (ctr = startByte; ctr < startByte+numTraversedBytes; ctr++)
  4139.                 {
  4140.                     dest[destIndex] = source[ctr];
  4141.                     destIndex++;
  4142.                 }
  4143.             }
  4144.         }
  4145.         while (index < lineLength);
  4146.  
  4147.     return destIndex;    //return a number that is the num of bytes in the destination
  4148. }
  4149.  
  4150.  
  4151.  
  4152. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4153. //    Method:        Invert:In
  4154. //    Parameters:    A number of bytes to convert, and the buffer to do it in.
  4155. //    Returns:     self
  4156. //    Stores:        none
  4157. //    Description:
  4158. //        This simply inverts numBytes bytes in theBuffer.  
  4159. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4160. - Invert: (Integer) numBytes In: (ByteString) theBuffer;
  4161. {
  4162.     Integer    index;
  4163.     for (index = 0; index < numBytes; index++)
  4164.         theBuffer[index] = ~(theBuffer[index]);
  4165.     return self;
  4166. }
  4167.  
  4168.  
  4169. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4170. //    Method:        Copy:BitsAtOffset:From:Into:
  4171. //    Parameters:    The number of bits in the source data to be copied
  4172. //                The number of bits, offset from the start of source, where source data starts
  4173. //                The source byte string to copy from
  4174. //                The destination byte string to copy into
  4175. //    Returns:     The destination pointer (identical to the one passed)
  4176. //    Stores:        error code
  4177. //                1 The destination pointer (as a Pointer)
  4178. //                2 The count of the number of bytes stored in the destination
  4179. //    Description:
  4180. //        This routine can be used to extract arbitrary bit patterns out of a source string.
  4181. //        It was created to serve two different purposes: to allow one to get a bitmap from
  4182. //        a PICT image so it was left justified in its storage space, rather than offset some
  4183. //        number of bits in.  The other use was to extract the characters of a Mac font,
  4184. //        one scanline at a time, from the single bitmap tht makes up a Mac font.
  4185. //        Ultimately, the work is simple: take a source string, and an offset into it where
  4186. //        the data resides (and the length of the source data).  Copy the relevant bits from
  4187. //        the source to the dest.  Note that this aligns the left of the source data to the
  4188. //        beginning of a byte boundrary in dest.  Also note that it fills up an integral number
  4189. //        of bytes in dest, filling the last out with 0's if needed.
  4190. //    Bugs:
  4191. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4192. - (ByteString) Copy: (PositiveInteger) sourceSize
  4193.     BitsAtOffset: (PositiveInteger) offset
  4194.     From: (ByteString) source
  4195.     Into: (ByteString) dest
  4196. {
  4197.     PositiveInteger    firstByte, lastByte;    // First and last bytes in source string to be copied
  4198.     PositiveInteger    index, destIndex;        // indices into source and dest strings
  4199.     PositiveInteger    offsetInByte;            // Number of bits into a byte a dest byte starts
  4200.     Byte            byte1, byte2;            // Temporary bytes to hold info as copied
  4201.     
  4202.     Byte    mask;
  4203.     PositiveInteger    bitpos, bitsMoved, finalBits;
  4204.     
  4205.     [self    ResetResults];
  4206.     
  4207.     if (sourceSize == 0)
  4208.     {
  4209.         [self   StoreErrorCode: ERR_BADSOURCESIZE
  4210.             AndText: "You requested for 0 bytes.  This has been fulfilled, weird as it is."];
  4211.         dest[0] = 0;
  4212.         [self   StorePointer: (Pointer) dest];
  4213.         [self   PutPositiveInteger: 0 Into: SECOND_RESULT];
  4214.     }
  4215.     else
  4216.     {
  4217.         //
  4218.         //    Computer our start and end position in source string, in bytes, and compute what
  4219.         //    bit offset in the first byte we should start working at
  4220.         //
  4221.         firstByte = offset / 8;
  4222.         lastByte = ((offset+sourceSize-1) / 8);
  4223.         offsetInByte = offset % 8;    // Zero origin...
  4224.         //
  4225.         //    Bear in mind that it's most likely that the destination byte will straddle two bytes
  4226.         //    in the source string.  So.  Get two bytes at a time from the source, and bitshift
  4227.         //    so they each contain only the bits that are relevant to the destination byte (get its
  4228.         //    upper and lower parts), then fuse the two parts together into a single destination
  4229.         //    byte.  Increment our destination index, and store the upper of the two bytes, for
  4230.         //    it will be the lower one the next time around. 
  4231.         //    Following this, deal with any remaining bits that might belong to the final
  4232.         //    dest byte, and pad them with zero.
  4233.         //
  4234.         destIndex = 0;
  4235.         //
  4236.         //    Two major cases: our data resides in only a single byte, or it spans
  4237.         //    two or more bytes:
  4238.         //
  4239.         if (firstByte == lastByte)
  4240.         {
  4241.             //
  4242.             //    First, shift the data in the byte down so it is aligned with the start
  4243.             //    of the byte.
  4244.             //    Then Build a mask to clear out any extraneous bits that were above the
  4245.             //    source data.  We're too lazy to actully determine whether there is any
  4246.             //    junk (there would be if the offset to the data + the length < 8 bits), and
  4247.             //    so, build a mask of sourceSize length, and use it.
  4248.             //
  4249.             byte1 = source[firstByte] << offsetInByte;
  4250.             mask = 0x00;
  4251.             for (bitpos = 0; bitpos < sourceSize; bitpos ++)
  4252.             {
  4253.                 mask = mask >> 1;
  4254.                 mask |= 0x80;
  4255.             }
  4256.             dest[destIndex] = byte1 &  mask;
  4257.             destIndex++;
  4258.         }
  4259.         else
  4260.         {
  4261.             //
  4262.             //    Start off by pulling off contiguous groups of 8 bits from
  4263.             //    the source, and storing them as bytes in the destination.
  4264.             //
  4265.             for (index = firstByte; index < lastByte; index++)
  4266.             {
  4267.                 byte1 = source[index] << offsetInByte;
  4268.                 byte2 = source[index+1] >> ( 8 - offsetInByte);
  4269.                 
  4270.                 dest[destIndex] = byte1 | byte2;
  4271.                 destIndex++;
  4272.             }
  4273.             //
  4274.             //    There are 3 possible states at this point:
  4275.             //    - We happen to have copied exactly the number of source bits to the dest.
  4276.             //    - We have copied too many bits to the dest (i.e. our final byte2 group had
  4277.             //        too many source bits in it)
  4278.             //    - We have not copied enough bits (i.e. there were bits in source[lastByte] that
  4279.             //        were not moved with those in byte2).
  4280.             //    Process each of these accordingly.
  4281.             //
  4282.             //    Calculate:
  4283.             //        Bits copied to dest in byte2:
  4284.             //        Bits source bits actually in source[lastbyte]
  4285.             //
  4286.             bitsMoved = offsetInByte;
  4287.             finalBits = (offset+sourceSize) - (lastByte*8);
  4288.             //
  4289.             //    There are a few bits which we have not yet moved.
  4290.             //
  4291.             if (finalBits > bitsMoved)
  4292.             {
  4293.                 byte1 = source[index] << bitsMoved;
  4294.                 mask = 0x00;
  4295.                 for (bitpos = 0; bitpos < (finalBits - bitsMoved); bitpos ++)
  4296.                 {
  4297.                     mask = mask >> 1;
  4298.                     mask |= 0x80;
  4299.                 }
  4300.                 dest[destIndex] = byte1 & mask;
  4301.                 destIndex++;
  4302.             }
  4303.             //
  4304.             //    Check if we moved more bits than we should have
  4305.             //
  4306.             else  if (finalBits < bitsMoved)
  4307.             {
  4308.                 mask = 0x00;
  4309.                 for (bitpos = 0; bitpos < finalBits+( 8 - offsetInByte); bitpos ++)
  4310.                 {
  4311.                     mask = mask >> 1;
  4312.                     mask |= 0x80;
  4313.                 }
  4314.                 dest[destIndex-1] = dest[destIndex-1] & mask;
  4315.             }
  4316.         }
  4317.     
  4318.         [self   StoreErrorCode: ERR_OK AndText: "No errors (big surprise)"];
  4319.         [self   StorePointer: (Pointer) dest];
  4320.         [self   PutPositiveInteger: destIndex Into: SECOND_RESULT];
  4321.     }
  4322.  
  4323.     return dest;
  4324. }
  4325.  
  4326. @end
  4327.